VTK/Wrapping Special Types

From KitwarePublic
Jump to navigationJump to search

This project began on April 28, 2010 and arose from a desire to improve the ability of the VTK wrappers to handle special VTK types, i.e. types that are not derived from vtkObjectBase. The primary goals are to wrap vtkVariant, and to fix the wrapping of vtkStdString since the current code will sometimes push an invalid "const char *" to the wrapper language.

Background

There are some very useful classes in VTK that are not derived from vtkObjectBase and are therefore not wrapped. Some, like vtkTimeStamp, are trivial classes. Others, like vtkVariant, are more comprehensive. The vtkStdString isn't wrapped, but is coerced to "const char *" by the wrappers in a manner that can leave dangling references to temporary objects.

State of the code

The wrapper generator code is a mess of hexidecimal literals, static variables, and badly-named functions. It should be updated to VTK code standards, in both the front-end and the back-end. This process has been started by the addition of vtkParseType.h, which defines useful macros for use by the wrapper code.

The vtkStdString issue

When vtkStdString was introduced to VTK, support for it was added to the wrappers in the following manner:

If a VTK method returned a vtkStdString or vtkStdString&, it would be stored in a "const char *" variable. Because type conversion from "string" to "char *" is automatic, this required minimal changes to the wrappers. Code that originally handled "const char *" would now handle strings, as well.

This scheme works fine for methods that return "vtkStdString&" because the string is stored somewhere and is guaranteed to be around at least until the contents of the "char *" are copied or otherwise used by the wrapper language. However, methods returning "vtkStdString" are problematic, because they create a temporary vtkStdString object which the wrappers then get a "char *" from. As soon as the "char *" is acquired, the compiler is free to throw the temporary away, even before the wrappers have a chance to utilize the "char *".

The fix should be straightforward. When a method returns a vtkStdString, the wrappers should store it in a vtkStdString variable that remains valid until the wrappers have copied the contents. The only complication is that the vtkParse front end must define a new type constant for vtkStdString.

Changes Needed

New parser types for vtkStdString and vtkUnicodeString

These two types must be handled transparently by the wrapper languages, i.e. we want vtkStdString to be automatically converted the the wrapper language's native string type, as opposed to defining a special "vtkStdString" type in the wrapper language. In other words, we need to add two slots to the list of parse types. Unfortunately, the way that the parser types are enumerated (i.e. as hexidecimal digits), there are only 15 slots available, and 14 of those slots are used.

The parser internally uses 32-bit ints for types. The first 16 bits are used for the array count, e.g. "float arg[count]". The last 16 bits are used to store four hexadecimal digits that describe the following:

  • 1st digit: const (0x1) or static (0x2) or function pointer (0x5)
  • 2nd digit: reference (0x1) or pointer (0x3) and variations thereof up to 0x9
  • 3rd digit: unsigned (0x1)
  • 4th digit: base type (0x1 through 0xE)

This is poor usage of the available bits. If we squash the bitfield to remove bits that are always zero, then a full 8 bits or two hexadecimal digits can be reserved for the base type.

I have added a vtkParseType.h header file that defines the bitfields for the types, and have modified vtkParse so that it uses this header file. So it is now possible to change the type bitfields simply by changing vtkParseType.h.

Once this has been done, vtkStdString and vtkUnicodeString will be visible to vtkWrapPython.c and the other wrapper back-ends. The back-ends will have to be modified to convert back and forth between these types and the native string types of the wrapper languages.

Marking special classes in CMake

Unlike vtkStdString, we want vtkVariant to appear in the wrapper languages as a type called "vtkVariant" that has the same methods as the C++ class. In other words, we want it to be wrapped is a similar manner (but with some distinct differences) to vtkObjectBase-derived classes.

The differences between wrapping "special classes" like vtkVariant vs. vtkObjectBase-derived classes are:

  • special classes must not be added to the vtkInstantiators
  • special classes must always be handled with copy semantics in the wrappers, since they don't have reference counts
  • the wrapper languages will probably not handle polymorphism for special classes

Because of these differences, there must be a way of marking special classes within CMake. Right now, their header files are simply marked as "WRAP_EXCLUDE". They must instead be marked as "WRAP_SPECIAL" so that they can be kept out of the instantiators, while being sent to whatever language wrappers are able to handle them. It is likely that support for special classes will only be added to the python wrappers (unless there are volunteers for the other wrapper languages).

Status

30 April 2010

For python, vtkVariant and vtkTimeStamp are both automatically wrapped. There is an issue with constructors for vtkVariant that still needs to be fixed. The wrapper code tries out the various constructor signatures in order until one is able to use the constructor arguments. Because the "char" constructor is tried first, any attempt to make a "double" or "int" variant results in the creation of a "char" variant instead. Creating a variant from a string or a vtkObject works fine, though. Storing variants in a vtkVariantArray also works.

A problem was found with the parser: the leading "~" of the destructor signature is thrown away by the parser, so the destructor isn't distinguishable from a constructor.