diff options
author | Garrett Regier <garrett.regier@riftio.com> | 2015-01-27 10:39:53 -0800 |
---|---|---|
committer | Garrett Regier <garrett.regier@riftio.com> | 2015-02-16 11:37:48 -0800 |
commit | 60de632153a693fb2b0f2ce26208c6ff668bdf4d (patch) | |
tree | 5c26aa02171e283deda066383b5e525069fd7129 | |
parent | a4160892dd28ab1d656cef4d4059f3b3f95caf4a (diff) | |
download | pygobject-60de632153a693fb2b0f2ce26208c6ff668bdf4d.tar.gz |
Avoid copying bytearrays from Python to C when transfer nothing
https://bugzilla.gnome.org/show_bug.cgi?id=743278
-rw-r--r-- | gi/pygi-array.c | 23 | ||||
-rw-r--r-- | tests/test_gi.py | 14 |
2 files changed, 32 insertions, 5 deletions
diff --git a/gi/pygi-array.c b/gi/pygi-array.c index e2598cd3..121992b6 100644 --- a/gi/pygi-array.c +++ b/gi/pygi-array.c @@ -191,6 +191,7 @@ _pygi_marshal_from_py_array (PyGIInvokeState *state, GArray *array_ = NULL; PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache; + GITransfer cleanup_transfer = arg_cache->transfer; if (py_arg == Py_None) { @@ -234,7 +235,21 @@ _pygi_marshal_from_py_array (PyGIInvokeState *state, if (sequence_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8 && PYGLIB_PyBytes_Check (py_arg)) { - memcpy(array_->data, PYGLIB_PyBytes_AsString (py_arg), length); + gchar *data = PYGLIB_PyBytes_AsString (py_arg); + + /* Avoid making a copy if the data + * is not transferred to the C function + * and cannot not be modified by it. + */ + if (array_cache->array_type == GI_ARRAY_TYPE_C && + arg_cache->transfer == GI_TRANSFER_NOTHING && + !array_cache->is_zero_terminated) { + g_free (array_->data); + array_->data = data; + cleanup_transfer = GI_TRANSFER_EVERYTHING; + } else { + memcpy (array_->data, data, length); + } array_->len = length; if (array_cache->is_zero_terminated) { /* If array_ has been created with zero_termination, space for the @@ -385,7 +400,7 @@ array_success: */ arg->v_pointer = array_->data; - if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) { + if (cleanup_transfer == GI_TRANSFER_EVERYTHING) { g_array_free (array_, FALSE); *cleanup_data = NULL; } else { @@ -394,10 +409,10 @@ array_success: } else { arg->v_pointer = array_; - if (arg_cache->transfer == GI_TRANSFER_NOTHING) { + if (cleanup_transfer == GI_TRANSFER_NOTHING) { /* Free everything in cleanup. */ *cleanup_data = array_; - } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) { + } else if (cleanup_transfer == GI_TRANSFER_CONTAINER) { /* Make a shallow copy so we can free the elements later in cleanup * because it is possible invoke will free the list before our cleanup. */ *cleanup_data = is_ptr_array ? diff --git a/tests/test_gi.py b/tests/test_gi.py index 31b31f58..f85d60fb 100644 --- a/tests/test_gi.py +++ b/tests/test_gi.py @@ -1089,7 +1089,19 @@ class TestGByteArray(unittest.TestCase): self.assertEqual(b'\x001\xFF3', GIMarshallingTests.bytearray_full_return()) def test_bytearray_none_in(self): - GIMarshallingTests.bytearray_none_in(b'\x00\x31\xFF\x33') + b = b'\x00\x31\xFF\x33' + ba = GLib.ByteArray.new_take(b) + + # b should always have the same value even + # though the generated GByteArray is being modified + GIMarshallingTests.bytearray_none_in(b) + GIMarshallingTests.bytearray_none_in(b) + + # The GByteArray is just a bytes + # thus it will not reflect any changes + GIMarshallingTests.bytearray_none_in(ba) + GIMarshallingTests.bytearray_none_in(ba) + #self.assertEqual(ba, b'\x00\x31\x00\x33') class TestGList(unittest.TestCase): |