Commit c48ddacf authored by Simon Feltman's avatar Simon Feltman

cache refactoring: Break sequence cache up for array vs list

Add new arg cache type specialized for arrays. This cleans up the basic
sequence cache type which does not need length and size related info. Remove
fixed length checks from GList and GSList from_py marshaling because these
will always be -1.

https://bugzilla.gnome.org/show_bug.cgi?id=709700
parent c1a2a86a
......@@ -159,6 +159,15 @@ _sequence_cache_free_func (PyGISequenceCache *cache)
}
}
static void
_array_cache_free_func (PyGIArgGArray *cache)
{
if (cache != NULL) {
_pygi_arg_cache_free (((PyGISequenceCache *)cache)->item_cache);
g_slice_free (PyGIArgGArray, cache);
}
}
static void
_callback_cache_free_func (PyGICallbackCache *cache)
{
......@@ -206,27 +215,26 @@ _interface_cache_new (GIInterfaceInfo *iface_info)
return ic;
}
static PyGISequenceCache *
_sequence_cache_new (GITypeInfo *type_info,
GIDirection direction,
GITransfer transfer,
gssize child_offset)
gboolean
pygi_arg_sequence_setup (PyGISequenceCache *sc,
GITypeInfo *type_info,
GIArgInfo *arg_info, /* may be NULL for return arguments */
GITransfer transfer,
PyGIDirection direction)
{
PyGISequenceCache *sc;
GITypeInfo *item_type_info;
GITransfer item_transfer;
sc = g_slice_new0 (PyGISequenceCache);
( (PyGIArgCache *)sc)->destroy_notify = (GDestroyNotify)_sequence_cache_free_func;
sc->is_zero_terminated = g_type_info_is_zero_terminated (type_info);
sc->fixed_size = g_type_info_get_array_fixed_size (type_info);
sc->len_arg_index = g_type_info_get_array_length (type_info);
if (sc->len_arg_index >= 0)
sc->len_arg_index += child_offset;
if (!pygi_arg_base_setup ((PyGIArgCache *)sc,
type_info,
arg_info,
transfer,
direction)) {
return FALSE;
}
sc->arg_cache.destroy_notify = (GDestroyNotify)_sequence_cache_free_func;
item_type_info = g_type_info_get_param_type (type_info, 0);
item_transfer =
transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
......@@ -237,17 +245,89 @@ _sequence_cache_new (GITypeInfo *type_info,
0, 0,
NULL);
g_base_info_unref ( (GIBaseInfo *)item_type_info);
if (sc->item_cache == NULL) {
_pygi_arg_cache_free ( (PyGIArgCache *)sc);
return NULL;
return FALSE;
}
return TRUE;
}
static gboolean
pygi_arg_garray_setup (PyGIArgGArray *sc,
GITypeInfo *type_info,
GIArgInfo *arg_info, /* may be NULL for return arguments */
GITransfer transfer,
PyGIDirection direction,
gssize child_offset)
{
GITypeInfo *item_type_info;
if (!pygi_arg_sequence_setup ((PyGISequenceCache *)sc,
type_info,
arg_info,
transfer,
direction)) {
return FALSE;
}
((PyGIArgCache *)sc)->destroy_notify = (GDestroyNotify)_array_cache_free_func;
sc->is_zero_terminated = g_type_info_is_zero_terminated (type_info);
sc->fixed_size = g_type_info_get_array_fixed_size (type_info);
sc->len_arg_index = g_type_info_get_array_length (type_info);
if (sc->len_arg_index >= 0)
sc->len_arg_index += child_offset;
item_type_info = g_type_info_get_param_type (type_info, 0);
sc->item_size = _pygi_g_type_info_size (item_type_info);
g_base_info_unref ( (GIBaseInfo *)item_type_info);
return TRUE;
}
static PyGISequenceCache *
pygi_arg_sequence_new (GITypeInfo *type_info,
GIArgInfo *arg_info,
GITransfer transfer,
PyGIDirection direction)
{
PyGISequenceCache *sc = g_slice_new0 (PyGISequenceCache);
if (sc == NULL)
return NULL;
if (!pygi_arg_sequence_setup (sc, type_info, arg_info, transfer, direction)) {
_pygi_arg_cache_free ( (PyGIArgCache *)sc);
return NULL;
}
return sc;
}
static PyGIArgGArray *
_arg_array_cache_new (GITypeInfo *type_info,
GIArgInfo *arg_info,
GITransfer transfer,
PyGIDirection direction,
gssize child_offset)
{
PyGIArgGArray *array_cache = g_slice_new0 (PyGIArgGArray);
if (array_cache == NULL)
return NULL;
if (!pygi_arg_garray_setup (array_cache,
type_info,
arg_info,
transfer,
direction,
child_offset)) {
_pygi_arg_cache_free ( (PyGIArgCache *)array_cache);
return NULL;
}
return array_cache;
}
static PyGICallbackCache *
_callback_cache_new (GIArgInfo *arg_info,
GIInterfaceInfo *iface_info,
......@@ -284,7 +364,7 @@ _arg_cache_array_len_arg_setup (PyGIArgCache *arg_cache,
gssize arg_index,
gssize *py_arg_index)
{
PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
PyGIArgGArray *seq_cache = (PyGIArgGArray *)arg_cache;
if (seq_cache->len_arg_index >= 0) {
PyGIArgCache *child_cache = NULL;
......@@ -357,7 +437,7 @@ _arg_cache_from_py_array_setup (PyGIArgCache *arg_cache,
PyGIDirection direction,
gssize arg_index)
{
PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
PyGIArgGArray *seq_cache = (PyGIArgGArray *)arg_cache;
seq_cache->array_type = g_type_info_get_array_type (type_info);
arg_cache->from_py_marshaller = _pygi_marshal_from_py_array;
arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_array;
......@@ -372,7 +452,7 @@ _arg_cache_to_py_array_setup (PyGIArgCache *arg_cache,
PyGIDirection direction,
gssize arg_index)
{
PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
PyGIArgGArray *seq_cache = (PyGIArgGArray *)arg_cache;
seq_cache->array_type = g_type_info_get_array_type (type_info);
arg_cache->to_py_marshaller = _pygi_marshal_to_py_array;
arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_array;
......@@ -706,11 +786,12 @@ _arg_cache_new (GITypeInfo *type_info,
case GI_TYPE_TAG_ARRAY:
{
PyGISequenceCache *seq_cache =
_sequence_cache_new (type_info,
direction,
transfer,
child_offset);
PyGIArgGArray *seq_cache =
_arg_array_cache_new (type_info,
arg_info,
transfer,
direction,
child_offset);
arg_cache = (PyGIArgCache *)seq_cache;
if (arg_cache == NULL)
......@@ -738,15 +819,17 @@ _arg_cache_new (GITypeInfo *type_info,
c_arg_index,
&py_arg_index);
break;
arg_cache->py_arg_index = py_arg_index;
arg_cache->c_arg_index = c_arg_index;
return arg_cache;
}
case GI_TYPE_TAG_GLIST:
{
PyGISequenceCache *seq_cache =
_sequence_cache_new (type_info,
direction,
transfer,
child_offset);
pygi_arg_sequence_new (type_info,
arg_info,
transfer,
direction);
arg_cache = (PyGIArgCache *)seq_cache;
if (arg_cache == NULL)
......@@ -758,16 +841,17 @@ _arg_cache_new (GITypeInfo *type_info,
if (direction & PYGI_DIRECTION_TO_PYTHON)
_arg_cache_to_py_glist_setup (arg_cache, transfer);
break;
arg_cache->py_arg_index = py_arg_index;
arg_cache->c_arg_index = c_arg_index;
return arg_cache;
}
case GI_TYPE_TAG_GSLIST:
{
PyGISequenceCache *seq_cache =
_sequence_cache_new (type_info,
direction,
transfer,
child_offset);
pygi_arg_sequence_new (type_info,
arg_info,
transfer,
direction);
arg_cache = (PyGIArgCache *)seq_cache;
if (arg_cache == NULL)
......@@ -779,7 +863,9 @@ _arg_cache_new (GITypeInfo *type_info,
if (direction & PYGI_DIRECTION_TO_PYTHON)
_arg_cache_to_py_gslist_setup (arg_cache, transfer);
break;
arg_cache->py_arg_index = py_arg_index;
arg_cache->c_arg_index = c_arg_index;
return arg_cache;
}
case GI_TYPE_TAG_GHASH:
arg_cache = pygi_arg_hash_table_new_from_info (type_info, arg_info, transfer, direction);
......
......@@ -132,13 +132,18 @@ struct _PyGIArgCache
typedef struct _PyGISequenceCache
{
PyGIArgCache arg_cache;
PyGIArgCache *item_cache;
} PyGISequenceCache;
typedef struct _PyGIArgGArray
{
PyGISequenceCache seq_cache;
gssize fixed_size;
gssize len_arg_index;
gboolean is_zero_terminated;
gsize item_size;
GIArrayType array_type;
PyGIArgCache *item_cache;
} PyGISequenceCache;
} PyGIArgGArray;
typedef struct _PyGIInterfaceCache
{
......@@ -211,6 +216,13 @@ pygi_arg_interface_setup (PyGIInterfaceCache *iface_cache,
PyGIDirection direction,
GIInterfaceInfo *iface_info);
gboolean
pygi_arg_sequence_setup (PyGISequenceCache *sc,
GITypeInfo *type_info,
GIArgInfo *arg_info, /* may be NULL for return arguments */
GITransfer transfer,
PyGIDirection direction);
PyGIArgCache * _arg_cache_alloc (void);
PyGIArgCache * _arg_cache_new (GITypeInfo *type_info,
GIArgInfo *arg_info,
......
......@@ -422,9 +422,9 @@ static gboolean _caller_alloc (PyGIInvokeState *state,
state->args[arg_count]->v_pointer = g_malloc0 (size);
}
} else if (arg_cache->type_tag == GI_TYPE_TAG_ARRAY) {
PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
state->out_args[out_count].v_pointer = g_array_new (TRUE, TRUE, seq_cache->item_size);
state->out_args[out_count].v_pointer = g_array_new (TRUE, TRUE, array_cache->item_size);
state->args[arg_count] = &state->out_args[out_count];
} else {
return FALSE;
......
......@@ -297,24 +297,24 @@ _pygi_marshal_cleanup_to_py_interface_struct_foreign (PyGIInvokeState *state,
static GArray*
_wrap_c_array (PyGIInvokeState *state,
PyGISequenceCache *sequence_cache,
PyGIArgGArray *array_cache,
gpointer data)
{
GArray *array_;
gsize len = 0;
if (sequence_cache->fixed_size >= 0) {
len = sequence_cache->fixed_size;
} else if (sequence_cache->is_zero_terminated) {
if (array_cache->fixed_size >= 0) {
len = array_cache->fixed_size;
} else if (array_cache->is_zero_terminated) {
len = g_strv_length ((gchar **)data);
} else if (sequence_cache->len_arg_index >= 0) {
GIArgument *len_arg = state->args[sequence_cache->len_arg_index];
} else if (array_cache->len_arg_index >= 0) {
GIArgument *len_arg = state->args[array_cache->len_arg_index];
len = len_arg->v_long;
}
array_ = g_array_new (FALSE,
FALSE,
sequence_cache->item_size);
array_cache->item_size);
if (array_ == NULL)
return NULL;
......@@ -337,8 +337,9 @@ _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state,
GArray *array_ = NULL;
GPtrArray *ptr_array_ = NULL;
PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
if (sequence_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
if (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
ptr_array_ = (GPtrArray *) data;
} else {
array_ = (GArray *) data;
......@@ -363,7 +364,7 @@ _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state,
item = g_array_index (array_, gpointer, i);
/* case 3: C array or GArray with simple types or structs */
else {
item = array_->data + i * sequence_cache->item_size;
item = array_->data + i * array_cache->item_size;
/* special-case hack: GValue array items do not get slice
* allocated in _pygi_marshal_from_py_array(), so we must
* not try to deallocate it as a slice and thus
......@@ -381,7 +382,7 @@ _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state,
}
/* Only free the array when we didn't transfer ownership */
if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
if (array_cache->array_type == GI_ARRAY_TYPE_C) {
/* always free the GArray wrapper created in from_py marshaling and
* passed back as cleanup_data
*/
......@@ -407,16 +408,17 @@ _pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state,
GArray *array_ = NULL;
GPtrArray *ptr_array_ = NULL;
PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
/* If this isn't a garray create one to help process variable sized
array elements */
if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
array_ = _wrap_c_array (state, sequence_cache, data);
if (array_cache->array_type == GI_ARRAY_TYPE_C) {
array_ = _wrap_c_array (state, array_cache, data);
if (array_ == NULL)
return;
} else if (sequence_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
} else if (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
ptr_array_ = (GPtrArray *) data;
} else {
array_ = (GArray *) data;
......
......@@ -258,6 +258,7 @@ _pygi_marshal_from_py_array (PyGIInvokeState *state,
gboolean is_ptr_array;
GArray *array_ = NULL;
PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache;
PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
if (py_arg == Py_None) {
......@@ -275,20 +276,20 @@ _pygi_marshal_from_py_array (PyGIInvokeState *state,
if (length < 0)
return FALSE;
if (sequence_cache->fixed_size >= 0 &&
sequence_cache->fixed_size != length) {
if (array_cache->fixed_size >= 0 &&
array_cache->fixed_size != length) {
PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd",
sequence_cache->fixed_size, length);
array_cache->fixed_size, length);
return FALSE;
}
item_size = sequence_cache->item_size;
is_ptr_array = (sequence_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY);
item_size = array_cache->item_size;
is_ptr_array = (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY);
if (is_ptr_array) {
array_ = (GArray *)g_ptr_array_sized_new (length);
} else {
array_ = g_array_sized_new (sequence_cache->is_zero_terminated,
array_ = g_array_sized_new (array_cache->is_zero_terminated,
TRUE,
item_size,
length);
......@@ -303,7 +304,7 @@ _pygi_marshal_from_py_array (PyGIInvokeState *state,
PYGLIB_PyBytes_Check (py_arg)) {
memcpy(array_->data, PYGLIB_PyBytes_AsString (py_arg), length);
array_->len = length;
if (sequence_cache->is_zero_terminated) {
if (array_cache->is_zero_terminated) {
/* If array_ has been created with zero_termination, space for the
* terminator is properly allocated, so we're not off-by-one here. */
array_->data[length] = '\0';
......@@ -433,10 +434,10 @@ err:
}
array_success:
if (sequence_cache->len_arg_index >= 0) {
if (array_cache->len_arg_index >= 0) {
/* we have an child arg to handle */
PyGIArgCache *child_cache =
_pygi_callable_cache_get_arg (callable_cache, sequence_cache->len_arg_index);
_pygi_callable_cache_get_arg (callable_cache, array_cache->len_arg_index);
if (child_cache->direction == PYGI_DIRECTION_BIDIRECTIONAL) {
gint *len_arg = (gint *)state->in_args[child_cache->c_arg_index].v_pointer;
......@@ -459,7 +460,7 @@ array_success:
}
}
if (sequence_cache->array_type == GI_ARRAY_TYPE_C) {
if (array_cache->array_type == GI_ARRAY_TYPE_C) {
/* In the case of GI_ARRAY_C, we give the data directly as the argument
* but keep the array_ wrapper as cleanup data so we don't have to find
* it's length again.
......@@ -523,14 +524,6 @@ _pygi_marshal_from_py_glist (PyGIInvokeState *state,
if (length < 0)
return FALSE;
if (sequence_cache->fixed_size >= 0 &&
sequence_cache->fixed_size != length) {
PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd",
sequence_cache->fixed_size, length);
return FALSE;
}
from_py_marshaller = sequence_cache->item_cache->from_py_marshaller;
for (i = 0; i < length; i++) {
GIArgument item = {0};
......@@ -607,14 +600,6 @@ _pygi_marshal_from_py_gslist (PyGIInvokeState *state,
if (length < 0)
return FALSE;
if (sequence_cache->fixed_size >= 0 &&
sequence_cache->fixed_size != length) {
PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd",
sequence_cache->fixed_size, length);
return FALSE;
}
from_py_marshaller = sequence_cache->item_cache->from_py_marshaller;
for (i = 0; i < length; i++) {
GIArgument item = {0};
......
......@@ -121,18 +121,19 @@ _pygi_marshal_to_py_array (PyGIInvokeState *state,
GArray *array_;
PyObject *py_obj = NULL;
PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache;
PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache;
gsize processed_items = 0;
/* GArrays make it easier to iterate over arrays
* with different element sizes but requires that
* we allocate a GArray if the argument was a C array
*/
if (seq_cache->array_type == GI_ARRAY_TYPE_C) {
if (array_cache->array_type == GI_ARRAY_TYPE_C) {
gsize len;
if (seq_cache->fixed_size >= 0) {
if (array_cache->fixed_size >= 0) {
g_assert(arg->v_pointer != NULL);
len = seq_cache->fixed_size;
} else if (seq_cache->is_zero_terminated) {
len = array_cache->fixed_size;
} else if (array_cache->is_zero_terminated) {
if (arg->v_pointer == NULL) {
len = 0;
} else if (seq_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8) {
......@@ -141,9 +142,9 @@ _pygi_marshal_to_py_array (PyGIInvokeState *state,
len = g_strv_length ((gchar **)arg->v_pointer);
}
} else {
GIArgument *len_arg = state->args[seq_cache->len_arg_index];
GIArgument *len_arg = state->args[array_cache->len_arg_index];
PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (callable_cache,
seq_cache->len_arg_index);
array_cache->len_arg_index);
if (!gi_argument_to_gsize (len_arg, &len, arg_cache->type_tag)) {
return NULL;
......@@ -152,7 +153,7 @@ _pygi_marshal_to_py_array (PyGIInvokeState *state,
array_ = g_array_new (FALSE,
FALSE,
seq_cache->item_size);
array_cache->item_size);
if (array_ == NULL) {
PyErr_NoMemory ();
......@@ -204,7 +205,7 @@ _pygi_marshal_to_py_array (PyGIInvokeState *state,
* and move on, letting the per-item marshaler deal with the
* various transfer modes and ref counts (e.g. g_variant_ref_sink).
*/
if (seq_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
if (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) {
item_arg.v_pointer = g_ptr_array_index ( ( GPtrArray *)array_, i);
} else if (item_arg_cache->is_pointer) {
......@@ -243,7 +244,7 @@ _pygi_marshal_to_py_array (PyGIInvokeState *state,
if (py_item == NULL) {
Py_CLEAR (py_obj);
if (seq_cache->array_type == GI_ARRAY_TYPE_C)
if (array_cache->array_type == GI_ARRAY_TYPE_C)
g_array_unref (array_);
goto err;
......@@ -254,13 +255,13 @@ _pygi_marshal_to_py_array (PyGIInvokeState *state,
}
}
if (seq_cache->array_type == GI_ARRAY_TYPE_C)
if (array_cache->array_type == GI_ARRAY_TYPE_C)
g_array_free (array_, FALSE);
return py_obj;
err:
if (seq_cache->array_type == GI_ARRAY_TYPE_C) {
if (array_cache->array_type == GI_ARRAY_TYPE_C) {
g_array_free (array_, arg_cache->transfer == GI_TRANSFER_EVERYTHING);
} else {
/* clean up unprocessed items */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment