Skip to content

Commit d6fe79a

Browse files
Allow more than one memoryview at a time
BasicIo is the only object that can't have more than one memoryview (mmap) so that needs separate treatment.
1 parent 562c3a9 commit d6fe79a

25 files changed

Lines changed: 648 additions & 557 deletions

src/interface/basicio.i

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,10 @@ OUTPUT_BUFFER_RW(Exiv2::byte* buf, size_t rcount)
135135
RETURN_VIEW(Exiv2::byte* mmap, $1 ? arg1->size() : 0,
136136
arg2 ? PyBUF_WRITE : PyBUF_READ,)
137137

138-
// Release memoryview when some functions are called
139-
%typemap(ret, fragment="release_view")
138+
// Release memoryviews when some functions are called
139+
%typemap(ret, fragment="memoryview_funcs")
140140
(int close), (int munmap), (long write), (size_t write) %{
141-
release_view(self);
141+
release_views(self);
142142
%}
143143

144144
// Enable len(Exiv2::BasicIo)

src/interface/image.i

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ INPUT_BUFFER_RO(const Exiv2::byte* data, size_t A)
7272

7373
// Release memory buffer after writeMetadata, as it creates its own copy
7474
%typemap(ret, fragment="private_data") void writeMetadata %{
75-
store_private(self, "_refers_to", NULL);
75+
private_store_del(self, "refers_to");
7676
%}
7777

7878
// Convert path encoding on Windows

src/interface/shared/buffers.i

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
%define INPUT_BUFFER_RO_EX(buf_type, len_type)
4646
INPUT_BUFFER_RO(buf_type, len_type)
4747
%typemap(argout, fragment="private_data") (buf_type, len_type) %{
48-
store_private(resultobj, "_refers_to", _global_view);
48+
private_store_set(resultobj, "refers_to", _global_view);
4949
%}
5050
%enddef // INPUT_BUFFER_RO_EX
5151

@@ -79,16 +79,34 @@ INPUT_BUFFER_RO(buf_type, len_type)
7979
%}
8080
%enddef // OUTPUT_BUFFER_RW
8181

82-
// Function to release any memoryview held in a weak ref
83-
%fragment("release_view", "header", fragment="private_data") {
84-
static int release_view(PyObject* py_self) {
85-
PyObject* ref = fetch_private(py_self, "view");
82+
// Functions to store references to memoryview objects and release them
83+
%fragment("memoryview_funcs", "header", fragment="private_data") {
84+
static int store_view(PyObject* py_self, PyObject* view,
85+
PyObject* callback=NULL) {
86+
PyObject* views = private_store_get(py_self, "views");
87+
if (!views) {
88+
views = PyList_New(0);
89+
private_store_set(py_self, "views", views);
90+
Py_DECREF(views);
91+
}
92+
PyObject* ref = PyWeakref_NewRef(view, callback);
8693
if (!ref)
87-
return 0;
88-
PyObject* view = PyWeakref_GetObject(ref);
89-
if (PyMemoryView_Check(view))
90-
Py_XDECREF(PyObject_CallMethod(view, "release", NULL));
94+
return -1;
95+
int result = PyList_Append(views, ref);
9196
Py_DECREF(ref);
97+
return result;
98+
};
99+
static int release_views(PyObject* py_self) {
100+
PyObject* views = private_store_get(py_self, "views");
101+
if (!views)
102+
return 0;
103+
PyObject* view = NULL;
104+
for (Py_ssize_t idx = PyList_Size(views); idx > 0; idx--) {
105+
view = PyWeakref_GetObject(PyList_GetItem(views, idx - 1));
106+
if (PyMemoryView_Check(view))
107+
Py_XDECREF(PyObject_CallMethod(view, "release", NULL));
108+
}
109+
private_store_del(py_self, "views");
92110
return 0;
93111
};
94112
}
@@ -97,15 +115,12 @@ static int release_view(PyObject* py_self) {
97115
// WARNING: return value does not keep a reference to the data it points to
98116
%define RETURN_VIEW(signature, size_func, flags, doc_method)
99117
%typemap(doctype) signature "memoryview";
100-
%typemap(out, fragment="private_data",
101-
fragment="release_view") (signature) %{
118+
%typemap(out, fragment="memoryview_funcs") (signature) %{
102119
$result = PyMemoryView_FromMemory((char*)$1, size_func, flags);
103120
if (!$result)
104121
SWIG_fail;
105-
// Release any existing memoryview
106-
release_view(self);
107122
// Store a weak ref to the new memoryview
108-
if (store_private(self, "view", PyWeakref_NewRef($result, NULL), true))
123+
if (store_view(self, $result))
109124
SWIG_fail;
110125
%}
111126
#if #doc_method != ""

src/interface/shared/keep_reference.i

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
// Functions to store and retrieve "private" data attached to Pyhon object
2020
%fragment("private_data", "header") {
2121
static PyObject* _get_store(PyObject* py_self, bool create) {
22+
// Return a new reference
2223
if (!PyObject_HasAttrString(py_self, "_private_data_")) {
2324
if (!create)
2425
return NULL;
@@ -32,42 +33,39 @@ static PyObject* _get_store(PyObject* py_self, bool create) {
3233
}
3334
return PyObject_GetAttrString(py_self, "_private_data_");
3435
};
35-
static int store_private(PyObject* py_self, const char* name,
36-
PyObject* val, bool take_ownership=false) {
37-
int result = 0;
36+
static int private_store_set(PyObject* py_self, const char* name,
37+
PyObject* val) {
3838
PyObject* dict = _get_store(py_self, true);
39-
if (dict) {
40-
if (val)
41-
result = PyDict_SetItemString(dict, name, val);
42-
else if (PyDict_GetItemString(dict, name))
43-
result = PyDict_DelItemString(dict, name);
44-
Py_DECREF(dict);
45-
}
46-
else
47-
result = -1;
48-
if (take_ownership && val)
49-
Py_DECREF(val);
39+
if (!dict)
40+
return -1;
41+
int result = PyDict_SetItemString(dict, name, val);
42+
Py_DECREF(dict);
5043
return result;
5144
};
52-
static PyObject* fetch_private(PyObject* py_self, const char* name) {
45+
static PyObject* private_store_get(PyObject* py_self, const char* name) {
46+
// Return a borrowed reference
5347
PyObject* dict = _get_store(py_self, false);
5448
if (!dict)
5549
return NULL;
5650
PyObject* result = PyDict_GetItemString(dict, name);
57-
if (result) {
58-
Py_INCREF(result);
59-
PyDict_DelItemString(dict, name);
60-
}
6151
Py_DECREF(dict);
6252
return result;
6353
};
54+
static int private_store_del(PyObject* py_self, const char* name) {
55+
PyObject* dict = _get_store(py_self, false);
56+
if (!dict)
57+
return 0;
58+
if (PyDict_DelItemString(dict, name))
59+
PyErr_Clear();
60+
return 0;
61+
};
6462
}
6563

6664
// Macro to keep a reference to any object when returning a particular type.
6765
%define KEEP_REFERENCE_EX(return_type, target)
6866
%typemap(ret, fragment="private_data") return_type %{
6967
if ($result != Py_None)
70-
if (store_private($result, "_refers_to", target)) {
68+
if (private_store_set($result, "refers_to", target)) {
7169
SWIG_fail;
7270
}
7371
%}

src/interface/types.i

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -246,14 +246,14 @@ RETURN_VIEW(Exiv2::byte* data, arg1->DATABUF_SIZE, PyBUF_WRITE,
246246
Exiv2::DataBuf::data)
247247

248248
// Release memoryview when other functions are called
249-
%typemap(ret, fragment="release_view")
249+
%typemap(ret, fragment="memoryview_funcs")
250250
(void alloc), (void reset), (void resize) %{
251-
release_view(self);
251+
release_views(self);
252252
%}
253253
#if EXIV2_VERSION_HEX < 0x001c0000
254-
%typemap(ret, fragment="release_view")
254+
%typemap(ret, fragment="memoryview_funcs")
255255
(void free) %{
256-
release_view(self);
256+
release_views(self);
257257
%}
258258
#endif
259259

src/interface/value.i

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -507,9 +507,9 @@ RETURN_VIEW(const char* data, arg1->value_.size(), PyBUF_READ,
507507
return $self->value_.data();
508508
}
509509
}
510-
// Release memoryview when new data is read
511-
%typemap(ret, fragment="release_view") (int class::read) %{
512-
release_view(self);
510+
// Release memoryviews when new data is read
511+
%typemap(ret, fragment="memoryview_funcs") (int class::read) %{
512+
release_views(self);
513513
%}
514514
%enddef // RAW_STRING_DATA
515515
RAW_STRING_DATA(Exiv2::StringValueBase)

src/swig-0_27_7/basicio_wrap.cxx

Lines changed: 47 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4527,6 +4527,7 @@ SWIGINTERNINLINE PyObject*
45274527

45284528

45294529
static PyObject* _get_store(PyObject* py_self, bool create) {
4530+
// Return a new reference
45304531
if (!PyObject_HasAttrString(py_self, "_private_data_")) {
45314532
if (!create)
45324533
return NULL;
@@ -4540,45 +4541,60 @@ static PyObject* _get_store(PyObject* py_self, bool create) {
45404541
}
45414542
return PyObject_GetAttrString(py_self, "_private_data_");
45424543
};
4543-
static int store_private(PyObject* py_self, const char* name,
4544-
PyObject* val, bool take_ownership=false) {
4545-
int result = 0;
4544+
static int private_store_set(PyObject* py_self, const char* name,
4545+
PyObject* val) {
45464546
PyObject* dict = _get_store(py_self, true);
4547-
if (dict) {
4548-
if (val)
4549-
result = PyDict_SetItemString(dict, name, val);
4550-
else if (PyDict_GetItemString(dict, name))
4551-
result = PyDict_DelItemString(dict, name);
4552-
Py_DECREF(dict);
4553-
}
4554-
else
4555-
result = -1;
4556-
if (take_ownership && val)
4557-
Py_DECREF(val);
4547+
if (!dict)
4548+
return -1;
4549+
int result = PyDict_SetItemString(dict, name, val);
4550+
Py_DECREF(dict);
45584551
return result;
45594552
};
4560-
static PyObject* fetch_private(PyObject* py_self, const char* name) {
4553+
static PyObject* private_store_get(PyObject* py_self, const char* name) {
4554+
// Return a borrowed reference
45614555
PyObject* dict = _get_store(py_self, false);
45624556
if (!dict)
45634557
return NULL;
45644558
PyObject* result = PyDict_GetItemString(dict, name);
4565-
if (result) {
4566-
Py_INCREF(result);
4567-
PyDict_DelItemString(dict, name);
4568-
}
45694559
Py_DECREF(dict);
45704560
return result;
45714561
};
4562+
static int private_store_del(PyObject* py_self, const char* name) {
4563+
PyObject* dict = _get_store(py_self, false);
4564+
if (!dict)
4565+
return 0;
4566+
if (PyDict_DelItemString(dict, name))
4567+
PyErr_Clear();
4568+
return 0;
4569+
};
45724570

45734571

4574-
static int release_view(PyObject* py_self) {
4575-
PyObject* ref = fetch_private(py_self, "view");
4572+
static int store_view(PyObject* py_self, PyObject* view,
4573+
PyObject* callback=NULL) {
4574+
PyObject* views = private_store_get(py_self, "views");
4575+
if (!views) {
4576+
views = PyList_New(0);
4577+
private_store_set(py_self, "views", views);
4578+
Py_DECREF(views);
4579+
}
4580+
PyObject* ref = PyWeakref_NewRef(view, callback);
45764581
if (!ref)
4577-
return 0;
4578-
PyObject* view = PyWeakref_GetObject(ref);
4579-
if (PyMemoryView_Check(view))
4580-
Py_XDECREF(PyObject_CallMethod(view, "release", NULL));
4582+
return -1;
4583+
int result = PyList_Append(views, ref);
45814584
Py_DECREF(ref);
4585+
return result;
4586+
};
4587+
static int release_views(PyObject* py_self) {
4588+
PyObject* views = private_store_get(py_self, "views");
4589+
if (!views)
4590+
return 0;
4591+
PyObject* view = NULL;
4592+
for (Py_ssize_t idx = PyList_Size(views); idx > 0; idx--) {
4593+
view = PyWeakref_GetObject(PyList_GetItem(views, idx - 1));
4594+
if (PyMemoryView_Check(view))
4595+
Py_XDECREF(PyObject_CallMethod(view, "release", NULL));
4596+
}
4597+
private_store_del(py_self, "views");
45824598
return 0;
45834599
};
45844600

@@ -5094,7 +5110,7 @@ SWIGINTERN PyObject *_wrap_BasicIo_close(PyObject *self, PyObject *args) {
50945110
}
50955111
resultobj = SWIG_From_int(static_cast< int >(result));
50965112

5097-
release_view(self);
5113+
release_views(self);
50985114

50995115
return resultobj;
51005116
fail:
@@ -5148,7 +5164,7 @@ SWIGINTERN PyObject *_wrap_BasicIo_write__SWIG_0(PyObject *self, PyObject *args)
51485164
Py_XDECREF(_global_view);
51495165

51505166

5151-
release_view(self);
5167+
release_views(self);
51525168

51535169
return resultobj;
51545170
fail:
@@ -5199,7 +5215,7 @@ SWIGINTERN PyObject *_wrap_BasicIo_write__SWIG_1(PyObject *self, PyObject *args)
51995215
}
52005216
resultobj = SWIG_From_long(static_cast< long >(result));
52015217

5202-
release_view(self);
5218+
release_views(self);
52035219

52045220
return resultobj;
52055221
fail:
@@ -5612,10 +5628,8 @@ SWIGINTERN PyObject *_wrap_BasicIo_mmap(PyObject *self, PyObject *args) {
56125628
resultobj = PyMemoryView_FromMemory((char*)result, result ? arg1->size() : 0, arg2 ? PyBUF_WRITE : PyBUF_READ);
56135629
if (!resultobj)
56145630
SWIG_fail;
5615-
// Release any existing memoryview
5616-
release_view(self);
56175631
// Store a weak ref to the new memoryview
5618-
if (store_private(self, "view", PyWeakref_NewRef(resultobj, NULL), true))
5632+
if (store_view(self, resultobj))
56195633
SWIG_fail;
56205634

56215635
return resultobj;
@@ -5652,7 +5666,7 @@ SWIGINTERN PyObject *_wrap_BasicIo_munmap(PyObject *self, PyObject *args) {
56525666
}
56535667
resultobj = SWIG_From_int(static_cast< int >(result));
56545668

5655-
release_view(self);
5669+
release_views(self);
56565670

56575671
return resultobj;
56585672
fail:
@@ -5875,7 +5889,7 @@ SWIGINTERN PyObject *_wrap_BasicIo_data(PyObject *self, PyObject *args) {
58755889
resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_DataContext, SWIG_POINTER_OWN | 0 );
58765890

58775891
if (resultobj != Py_None)
5878-
if (store_private(resultobj, "_refers_to", self)) {
5892+
if (private_store_set(resultobj, "refers_to", self)) {
58795893
SWIG_fail;
58805894
}
58815895

0 commit comments

Comments
 (0)