File: ext_refcounts.i

package info (click to toggle)
renderdoc 1.2%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 79,584 kB
  • sloc: cpp: 491,671; ansic: 285,823; python: 12,617; java: 11,345; cs: 7,181; makefile: 6,703; yacc: 5,682; ruby: 4,648; perl: 3,461; php: 2,119; sh: 2,068; lisp: 1,835; tcl: 1,068; ml: 747; xml: 137
file content (91 lines) | stat: -rw-r--r-- 3,499 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
///////////////////////////////////////////////////////////////////////////////////////////////
// handling of 'externally refcounted' C++ types. The idea here is we have a C++ type that's
// passed around by pointer, so we can potentially keep it wrapped as a pointer and access it
// from python by reference instead of converting to/from python and getting by-value semantics.
//
// We make a few assumptions about lifetime:
//  - Python allocated instances of these types are only ever borrowed by C++. ie. we might pass
//    them to C++ but we won't transfer ownership. Thus, the refcount can be tracked in python
//    entirely and be sure that we won't have dangling references on the C++ side.
//    (The only sensible way to ensure this is to make any C++ calls only use the pointer until
//     they return, either by only using it temporarily or making local duplicates).
//  - The reverse holds true - any C++ objects returned to python may be modified or passed around,
//    but will not be deleted until python is done with them.
//    (This kind of depends on the user's scripts to enforce that they keep the C++ object alive
//     until they're done with the object).
//  - Any lists of references are only ever modified from one side or another. This is a bit more
//    opaque but basically we require this so that if we have a list of pointers in python and we
//    take a ref on the python-owned object, that the C++ side doesn't then silently remove the
//    object behind our back and leak a reference.
//
// The general summary is - each side (C++/Python) should own objects allocated on its side, and
// treat any pointers/containers of pointers from the other side as somewhat temporary and read-only.

%define REFCOUNTED_TYPE(typeName)

// refcounted types have custom init/dealloc to update the external refcount
%feature("python:tp_init") typeName STRINGIZE(typeName##_init);
%feature("python:tp_dealloc") typeName STRINGIZE(typeName##_dealloc_destructor_closure);

%wrapper %{
// mostly identical to generated version, but registers with ExtRefcount
static int typeName##_init(PyObject *self, PyObject *args)
{
  typeName *result = MakeFromArgsTuple<typeName>(args);

  if(!result)
    return -1;

  PyObject *resultobj = SWIG_NewPointerObj((void *)result, SWIGTYPE_p_##typeName, SWIG_BUILTIN_INIT);

  if(resultobj == Py_None)
  {
    delete result;
    return -1;
  }

  ExtRefcount<typeName *>::NewPyObject(resultobj, result);

  return 0;
}

static PyObject *typeName##_dealloc(PyObject *self, PyObject *args)
{
  typeName *thisptr = NULL;

  int res = SWIG_ConvertPtr(self, (void **)&thisptr, SWIGTYPE_p_##typeName, SWIG_POINTER_DISOWN);
  if(!SWIG_IsOK(res))
    SWIG_exception_fail(SWIG_ArgError(res), "Invalid " #typeName " being deleted");

  ExtRefcount<typeName *>::DelPyObject(self, thisptr);
  delete thisptr;

  return SWIG_Py_Void();
fail:
  return NULL;
}

SWIGPY_DESTRUCTOR_CLOSURE(typeName##_dealloc)

%}

%enddef // %define REFCOUNTED_TYPE

// add a typemap for a refcounted array
%define DEFINE_REFCOUNTED_ARRAY(typeName)

%typemap(memberin) typeName {
  // remove a reference on all the old items
  for(size_t i = 0; i < $1.size(); i++)
    ExtRefcount<typeName::value_type>::Dec($1[i]);

  $1.clear();

  // copy the values
  $1.assign(*$input);

  // the input values were already ref'd as needed during the 'in' typemap to convert them in the
  // first place, so we just steal those references
}

%enddef // %define DEFINE_REFCOUNTED_ARRAY