This is an automated email from the git hooks/post-receive script. intrigeri pushed a commit to annotated tag rel-0-02-9 in repository libglib-object-introspection-perl.
commit f2b0048a62d775f28a4f88e651e0cb3d6a5a9c93 Author: Torsten Schönfeld <kaffeeti...@gmx.de> Date: Sat Feb 28 18:34:16 2015 +0100 array ↔ SV: support GArray, GPtrArray and GByteArray --- NEWS | 1 + gperl-i11n-marshal-array.c | 258 ++++++++++++++++++++++++++++++++++----------- t/arrays.t | 87 ++++++++++++++- 3 files changed, 281 insertions(+), 65 deletions(-) diff --git a/NEWS b/NEWS index 9e5e377..b0bcbf3 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ Overview of changes in Glib::Object::Introspection <next> ======================================================== * Add support for marshalling GVariants. +* Add support for marshalling GArrays, GPtrArrays and GByteArrays. * Support flat arrays when converting from C to Perl. Overview of changes in Glib::Object::Introspection 0.028 diff --git a/gperl-i11n-marshal-array.c b/gperl-i11n-marshal-array.c index 705a8b0..e5eb459 100644 --- a/gperl-i11n-marshal-array.c +++ b/gperl-i11n-marshal-array.c @@ -1,12 +1,67 @@ /* -*- mode: c; indent-tabs-mode: t; c-basic-offset: 8; -*- */ +/* Arrays containing non-basic types as non-pointers need to be treated + * specially. Prime example: GValue *values = g_new0 (GValue, n); + */ +static gboolean +_need_struct_value_semantics (GIArrayType array_type, GITypeInfo *param_info, GITypeTag param_tag) +{ + gboolean is_flat, need_struct_value_semantics; + + is_flat = + /* is a raw array, and ... */ + (GI_ARRAY_TYPE_C == array_type || GI_ARRAY_TYPE_ARRAY == array_type) && + /* ... contains a compound type, and... */ + !G_TYPE_TAG_IS_BASIC (param_tag) && + /* ... contains non-pointers */ + !g_type_info_is_pointer (param_info); + + need_struct_value_semantics = is_flat; + if (GI_TYPE_TAG_INTERFACE == param_tag) { + /* FIXME: Try to use the invocation info here to avoid getting + * the interface info again? */ + GIBaseInfo *interface_info = g_type_info_get_interface (param_info); + switch (g_base_info_get_type (interface_info)) { + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + need_struct_value_semantics = FALSE; + default: + break; + } + g_base_info_unref (interface_info); + } + + return need_struct_value_semantics; +} + static void -free_raw_array (gpointer raw_array) +_free_raw_array (gpointer raw_array) { dwarn ("free_raw_array %p\n", raw_array); g_free (raw_array); } +static void +_free_array (GArray *array) +{ + dwarn ("free_array %p\n", array); + g_array_free (array, TRUE); +} + +static void +_free_ptr_array (GPtrArray *array) +{ + dwarn ("free_ptr_array %p\n", array); + g_ptr_array_free (array, TRUE); +} + +static void +_free_byte_array (GByteArray *array) +{ + dwarn ("free_byte_array %p\n", array); + g_byte_array_free (array, TRUE); +} + /* This may call Perl code (via arg_to_sv), so it needs to be wrapped with * PUTBACK/SPAGAIN by the caller. */ static SV * @@ -15,75 +70,95 @@ array_to_sv (GITypeInfo *info, GITransfer transfer, GPerlI11nInvocationInfo *iinfo) { + GIArrayType array_type; + gpointer array = NULL, elements = NULL; GITypeInfo *param_info; - gboolean is_zero_terminated; GITypeTag param_tag; gsize item_size; GITransfer item_transfer; - gssize length, i; gboolean need_struct_value_semantics; + gssize length = -1, i; AV *av; if (pointer == NULL) { return &PL_sv_undef; } - is_zero_terminated = g_type_info_is_zero_terminated (info); + array_type = g_type_info_get_array_type (info); - /* FIXME: What about an array containing arrays of strings, where the - * outer array is GI_TRANSFER_EVERYTHING but the inner arrays are - * GI_TRANSFER_CONTAINER? */ - item_transfer = transfer == GI_TRANSFER_EVERYTHING - ? GI_TRANSFER_EVERYTHING - : GI_TRANSFER_NOTHING; +#define GET_LENGTH_AND_ELEMENTS(type, len_field, data_field) { \ + array = pointer; \ + length = ((type *) array)->len_field; \ + elements = ((type *) array)->data_field; } - if (is_zero_terminated) { - length = g_strv_length (pointer); - } else { - length = g_type_info_get_array_fixed_size (info); - if (length < 0) { - SV *conversion_sv; - gint length_pos = g_type_info_get_array_length (info); - g_assert (iinfo && iinfo->aux_args); - conversion_sv = arg_to_sv (&(iinfo->aux_args[length_pos]), - iinfo->arg_types[length_pos], - GI_TRANSFER_NOTHING, NULL); - length = SvIV (conversion_sv); - SvREFCNT_dec (conversion_sv); + switch (array_type) { + case GI_ARRAY_TYPE_C: + array = pointer; + elements = pointer; + if (g_type_info_is_zero_terminated (info)) { + length = g_strv_length (elements); + } else { + length = g_type_info_get_array_fixed_size (info); + if (length < 0) { + SV *conversion_sv; + gint length_pos = g_type_info_get_array_length (info); + g_assert (iinfo && iinfo->aux_args); + conversion_sv = arg_to_sv (&(iinfo->aux_args[length_pos]), + iinfo->arg_types[length_pos], + GI_TRANSFER_NOTHING, NULL); + length = SvIV (conversion_sv); + SvREFCNT_dec (conversion_sv); + } } + break; + case GI_ARRAY_TYPE_ARRAY: + GET_LENGTH_AND_ELEMENTS (GArray, len, data); + break; + case GI_ARRAY_TYPE_PTR_ARRAY: + GET_LENGTH_AND_ELEMENTS (GPtrArray, len, pdata); + break; + case GI_ARRAY_TYPE_BYTE_ARRAY: + GET_LENGTH_AND_ELEMENTS (GByteArray, len, data); + break; + default: + ccroak ("Unhandled array type %d", array_type); } +#undef GET_LENGTH_AND_ELEMENTS + if (length < 0) { ccroak ("Could not determine the length of the array"); } + + /* FIXME: What about an array containing arrays of strings, where the + * outer array is GI_TRANSFER_EVERYTHING but the inner arrays are + * GI_TRANSFER_CONTAINER? */ + item_transfer = transfer == GI_TRANSFER_EVERYTHING + ? GI_TRANSFER_EVERYTHING + : GI_TRANSFER_NOTHING; + param_info = g_type_info_get_param_type (info, 0); param_tag = g_type_info_get_tag (param_info); item_size = size_of_type_info (param_info); av = newAV (); - /* Arrays containing non-basic types as non-pointers need to be treated - * specially. Prime example: GValue *values = g_new0 (GValue, n); - */ need_struct_value_semantics = - /* is a compound type, and... */ - !G_TYPE_TAG_IS_BASIC (param_tag) && - /* ... a non-pointer is wanted */ - !g_type_info_is_pointer (param_info); + _need_struct_value_semantics (array_type, param_info, param_tag); - dwarn (" C array: pointer %p, length %"G_GSSIZE_FORMAT", item size %"G_GSIZE_FORMAT", " + dwarn (" C array: pointer %p, array %p, elements %p, " + "length %"G_GSSIZE_FORMAT", item size %"G_GSIZE_FORMAT", " "param_info %p with type tag %d (%s)\n", - pointer, - length, - item_size, + pointer, array, elements, + length, item_size, param_info, - g_type_info_get_tag (param_info), - g_type_tag_to_string (g_type_info_get_tag (param_info))); + param_tag, + g_type_tag_to_string (param_tag)); for (i = 0; i < length; i++) { GIArgument arg; SV *value; - gpointer element = pointer + ((gsize) i) * item_size; + gpointer element = elements + ((gsize) i) * item_size; if (need_struct_value_semantics) { raw_to_arg (&element, &arg, param_info); } else { @@ -94,8 +169,22 @@ array_to_sv (GITypeInfo *info, av_push (av, value); } - if (transfer >= GI_TRANSFER_CONTAINER) - g_free (pointer); + if (transfer >= GI_TRANSFER_CONTAINER) { + switch (array_type) { + case GI_ARRAY_TYPE_C: + _free_raw_array (array); + break; + case GI_ARRAY_TYPE_ARRAY: + _free_array (array); + break; + case GI_ARRAY_TYPE_PTR_ARRAY: + _free_ptr_array (array); + break; + case GI_ARRAY_TYPE_BYTE_ARRAY: + _free_byte_array (array); + break; + } + } g_base_info_unref ((GIBaseInfo *) param_info); @@ -109,16 +198,18 @@ sv_to_array (GITransfer transfer, GPerlI11nInvocationInfo *iinfo) { AV *av; + GIArrayType array_type; GITransfer item_transfer; GITypeInfo *param_info; GITypeTag param_tag; gint length_pos; gsize i, length; GPerlI11nArrayInfo *array_info = NULL; - GArray *array; - gpointer raw_array; - gboolean is_zero_terminated = FALSE; - gsize item_size; + gpointer array = NULL; + gpointer return_array; + GFunc return_array_free_func; + gboolean is_zero_terminated = FALSE; + gsize item_size; gboolean need_struct_value_semantics; dwarn ("%s: sv %p\n", G_STRFUNC, sv); @@ -140,6 +231,8 @@ sv_to_array (GITransfer transfer, if (!gperl_sv_is_array_ref (sv)) ccroak ("need an array ref to convert to GArray"); + array_type = g_type_info_get_array_type (type_info); + av = (AV *) SvRV (sv); item_transfer = transfer == GI_TRANSFER_CONTAINER @@ -153,19 +246,27 @@ sv_to_array (GITransfer transfer, g_type_tag_to_string (g_type_info_get_tag (param_info)), transfer); + need_struct_value_semantics = + _need_struct_value_semantics (array_type, param_info, param_tag); is_zero_terminated = g_type_info_is_zero_terminated (type_info); item_size = size_of_type_info (param_info); length = (gsize) (av_len (av) + 1); /* av_len always returns at least -1 */ - array = g_array_sized_new (is_zero_terminated, FALSE, item_size, length); - /* Arrays containing non-basic types as non-pointers need to be treated - * specially. Prime example: GValue *values = g_new0 (GValue, n); - */ - need_struct_value_semantics = - /* is a compound type, and... */ - !G_TYPE_TAG_IS_BASIC (param_tag) && - /* ... a non-pointer is wanted */ - !g_type_info_is_pointer (param_info); + switch (array_type) { + case GI_ARRAY_TYPE_C: + case GI_ARRAY_TYPE_ARRAY: + array = g_array_sized_new (is_zero_terminated, FALSE, item_size, length); + break; + case GI_ARRAY_TYPE_PTR_ARRAY: + array = g_ptr_array_sized_new (length); + g_ptr_array_set_size (array, length); + break; + case GI_ARRAY_TYPE_BYTE_ARRAY: + array = g_byte_array_sized_new (length); + g_byte_array_set_size (array, length); + break; + } + for (i = 0; i < length; i++) { SV **svp; svp = av_fetch (av, i, 0); @@ -177,14 +278,25 @@ sv_to_array (GITransfer transfer, sv_to_arg (*svp, &arg, NULL, param_info, item_transfer, TRUE, NULL); - if (need_struct_value_semantics) { - /* Copy from the memory area pointed to by - * arg.v_pointer. */ - g_array_insert_vals (array, i, arg.v_pointer, 1); - } else { - /* Copy from &arg, i.e. the memory area that is - * arg. */ - g_array_insert_val (array, i, arg); + switch (array_type) { + case GI_ARRAY_TYPE_C: + case GI_ARRAY_TYPE_ARRAY: + if (need_struct_value_semantics) { + /* Copy from the memory area pointed to by + * arg.v_pointer. */ + g_array_insert_vals (array, i, arg.v_pointer, 1); + } else { + /* Copy from &arg, i.e. the memory area that is + * arg. */ + g_array_insert_val (array, i, arg); + } + break; + case GI_ARRAY_TYPE_PTR_ARRAY: + ((GPtrArray *) array)->pdata[i] = arg.v_pointer; + break; + case GI_ARRAY_TYPE_BYTE_ARRAY: + ((GByteArray *) array)->data[i] = arg.v_uint8; + break; } } } @@ -195,11 +307,29 @@ sv_to_array (GITransfer transfer, array_info->length = length; } - raw_array = g_array_free (array, FALSE); - if (GI_TRANSFER_NOTHING == transfer) - free_after_call (iinfo, (GFunc) free_raw_array, raw_array); + return_array = array; + return_array_free_func = NULL; + switch (array_type) { + case GI_ARRAY_TYPE_C: + return_array = g_array_free (array, FALSE); + return_array_free_func = (GFunc) _free_raw_array; + break; + case GI_ARRAY_TYPE_ARRAY: + return_array_free_func = (GFunc) _free_array; + break; + case GI_ARRAY_TYPE_PTR_ARRAY: + return_array_free_func = (GFunc) _free_ptr_array; + break; + case GI_ARRAY_TYPE_BYTE_ARRAY: + return_array_free_func = (GFunc) _free_byte_array; + break; + } + + if (GI_TRANSFER_NOTHING == transfer) { + free_after_call (iinfo, return_array_free_func, return_array); + } g_base_info_unref ((GIBaseInfo *) param_info); - return raw_array; + return return_array; } diff --git a/t/arrays.t b/t/arrays.t index 5fc309d..ff2857a 100644 --- a/t/arrays.t +++ b/t/arrays.t @@ -6,13 +6,14 @@ use strict; use warnings; use utf8; -plan tests => 30; +plan tests => 68; ok (Regress::test_strv_in ([ '1', '2', '3' ])); my $int_array = [ 1, 2, 3 ]; is (Regress::test_array_int_in ($int_array), 6); is_deeply (Regress::test_array_int_out (), [0, 1, 2, 3, 4]); +# FIXME: This leaks. See <https://bugzilla.gnome.org/show_bug.cgi?id=745336>. is_deeply (Regress::test_array_int_inout ($int_array), [3, 4]); is (Regress::test_array_gint8_in ($int_array), 6); is (Regress::test_array_gint16_in ($int_array), 6); @@ -53,4 +54,88 @@ is (Regress::test_gslist_null_out (), undef); # ----------------------------------------------------------------------------- +my $int_array_ref = [-1..2]; +my $boxed_array_ref = [map { Glib::Boxed::new ('GI::BoxedStruct', long_ => $_) } (1, 2, 3)]; +my $string_array_ref = [qw/0 1 2/]; +my $byte_array_ref = [0, ord '1', 0xFF, ord '3']; + +# Init-like. +is_deeply ([GI::init_function ([qw/a b c/])], [Glib::TRUE, [qw/a b/]]); + +# Fixed size. +is_deeply (GI::array_fixed_int_return (), $int_array_ref); +is_deeply (GI::array_fixed_short_return (), $int_array_ref); +GI::array_fixed_int_in ($int_array_ref); +GI::array_fixed_short_in ($int_array_ref); +is_deeply (GI::array_fixed_out (), $int_array_ref); is_deeply (GI::array_fixed_out_struct (), [{long_ => 7, int8 => 6}, {long_ => 6, int8 => 7}]); +is_deeply (GI::array_fixed_inout ($int_array_ref), [reverse @$int_array_ref]); + +# Variable size. +is_deeply (GI::array_return (), $int_array_ref); +is_deeply ([GI::array_return_etc (23, 42)], [[23, 0, 1, 42], 23+42]); +GI::array_in ($int_array_ref); +GI::array_in_len_before ($int_array_ref); +GI::array_in_len_zero_terminated ($int_array_ref); +GI::array_string_in ([qw/foo bar/]); +GI::array_uint8_in ([map { ord } qw/a b c d/]); +GI::array_struct_in ($boxed_array_ref); +GI::array_struct_value_in ($boxed_array_ref); +GI::array_struct_take_in ($boxed_array_ref); +is ($boxed_array_ref->[2]->long_, 3); +GI::array_simple_struct_in ([map { { long_ => $_ } } (1, 2, 3)]); +GI::multi_array_key_value_in ([qw/one two three/], + [map { Glib::Object::Introspection::GValueWrapper->new ('Glib::Int', $_) } (1, 2, 3)]); +GI::array_enum_in ([qw/value1 value2 value3/]); +GI::array_in_guint64_len ($int_array_ref); +GI::array_in_guint8_len ($int_array_ref); +is_deeply (GI::array_out (), $int_array_ref); +is_deeply ([GI::array_out_etc (23, 42)], [[23, 0, 1, 42], 23+42]); +is_deeply (GI::array_inout ($int_array_ref), [-2..2]); +is_deeply ([GI::array_inout_etc (23, $int_array_ref, 42)], [[23, -1, 0, 1, 42], 23+42]); +GI::array_in_nonzero_nonlen (23, [map { ord } qw/a b c d/]); + +# Zero-terminated. +is_deeply (GI::array_zero_terminated_return (), $string_array_ref); +is (GI::array_zero_terminated_return_null (), undef); +is_deeply ([map { $_->long_ } @{GI::array_zero_terminated_return_struct ()}], + [42, 43, 44]); +GI::array_zero_terminated_in ($string_array_ref); +is_deeply (GI::array_zero_terminated_out (), $string_array_ref); +is_deeply (GI::array_zero_terminated_inout ($string_array_ref), [qw/-1 0 1 2/]); +# The variant stuff is tested in variants.t. + +# GArray. +is_deeply (GI::garray_int_none_return (), $int_array_ref); +is_deeply (GI::garray_uint64_none_return (), [0, "18446744073709551615"]); +is_deeply (GI::garray_utf8_none_return (), $string_array_ref); +is_deeply (GI::garray_utf8_container_return (), $string_array_ref); +is_deeply (GI::garray_utf8_full_return (), $string_array_ref); +GI::garray_int_none_in ($int_array_ref); +GI::garray_uint64_none_in ([0, "18446744073709551615"]); +GI::garray_utf8_none_in ($string_array_ref); +is_deeply (GI::garray_utf8_none_out (), $string_array_ref); +is_deeply (GI::garray_utf8_container_out (), $string_array_ref); +is_deeply (GI::garray_utf8_full_out (), $string_array_ref); +# FIXME: is_deeply (GI::garray_utf8_full_out_caller_allocated (), $string_array_ref); +is_deeply (GI::garray_utf8_none_inout ($string_array_ref), [-2..1]); +is_deeply (GI::garray_utf8_container_inout ($string_array_ref), [-2..1]); +# FIXME: This leaks. See <https://bugzilla.gnome.org/show_bug.cgi?id=745336>. +is_deeply (GI::garray_utf8_full_inout ($string_array_ref), [-2..1]); + +# GPtrArray. +is_deeply (GI::gptrarray_utf8_none_return (), $string_array_ref); +is_deeply (GI::gptrarray_utf8_container_return (), $string_array_ref); +is_deeply (GI::gptrarray_utf8_full_return (), $string_array_ref); +GI::gptrarray_utf8_none_in ($string_array_ref); +is_deeply (GI::gptrarray_utf8_none_out (), $string_array_ref); +is_deeply (GI::gptrarray_utf8_container_out (), $string_array_ref); +is_deeply (GI::gptrarray_utf8_full_out (), $string_array_ref); +is_deeply (GI::gptrarray_utf8_none_inout ($string_array_ref), [-2..1]); +is_deeply (GI::gptrarray_utf8_container_inout ($string_array_ref), [-2..1]); +# FIXME: This leaks. See <https://bugzilla.gnome.org/show_bug.cgi?id=745336>. +is_deeply (GI::gptrarray_utf8_full_inout ($string_array_ref), [-2..1]); + +# GByteArray. +is_deeply (GI::bytearray_full_return (), $byte_array_ref); +GI::bytearray_none_in ($byte_array_ref); -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libglib-object-introspection-perl.git _______________________________________________ Pkg-perl-cvs-commits mailing list Pkg-perl-cvs-commits@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-perl-cvs-commits