[perl-Glib-Object-Introspection] array ↔ SV: supp ort GArray, GPtrArray and GByteArray
- From: Torsten Schönfeld <tsch src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [perl-Glib-Object-Introspection] array ↔ SV: supp ort GArray, GPtrArray and GByteArray
- Date: Sat, 28 Feb 2015 17:34:46 +0000 (UTC)
commit f2b0048a62d775f28a4f88e651e0cb3d6a5a9c93
Author: Torsten Schönfeld <kaffeetisch 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);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]