[gjs] Support in arrays of any type
- From: Giovanni Campagna <gcampagna src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs] Support in arrays of any type
- Date: Thu, 19 May 2011 17:38:29 +0000 (UTC)
commit dde2278f4ff2876be91e1c06989166aa83a66d16
Author: Giovanni Campagna <gcampagna src gnome org>
Date: Sun Apr 3 18:25:48 2011 +0200
Support in arrays of any type
Adds support for converting JS Arrays to C arrays of any type, not
just integers as before. Includes new infrastructure for releasing
said arrays.
https://bugzilla.gnome.org/show_bug.cgi?id=646632
gi/arg.c | 182 +++++++++++++++++++++++++++++++++++++++++-
gi/arg.h | 8 ++-
gi/function.c | 25 +++++-
test/js/testGIMarshalling.js | 14 +++
4 files changed, 220 insertions(+), 9 deletions(-)
---
diff --git a/gi/arg.c b/gi/arg.c
index ebebbf7..d44e4d7 100644
--- a/gi/arg.c
+++ b/gi/arg.c
@@ -576,9 +576,112 @@ gjs_array_to_intarray(JSContext *context,
}
static JSBool
+gjs_array_to_floatarray(JSContext *context,
+ jsval array_value,
+ unsigned int length,
+ void **arr_p,
+ gboolean is_double)
+{
+ unsigned int i;
+ void *result = g_malloc0(length * (is_double ? sizeof(double) : sizeof(float)));
+
+ for (i = 0; i < length; ++i) {
+ jsval elem;
+ jsdouble val;
+ JSBool success;
+
+ elem = JSVAL_VOID;
+ if (!JS_GetElement(context, JSVAL_TO_OBJECT(array_value),
+ i, &elem)) {
+ g_free(result);
+ gjs_throw(context,
+ "Missing array element %u",
+ i);
+ return JS_FALSE;
+ }
+
+ /* do whatever sign extension is appropriate */
+ success = JS_ValueToNumber(context, elem, &val);
+
+ if (!success) {
+ g_free(result);
+ gjs_throw(context,
+ "Invalid element in array");
+ return JS_FALSE;
+ }
+
+ /* Note that this is truncating assignment. */
+ if (is_double) {
+ double *darray = (double*)result;
+ darray[i] = val;
+ } else {
+ float *farray = (float*)result;
+ farray[i] = val;
+ }
+ }
+
+ *arr_p = result;
+
+ return JS_TRUE;
+}
+
+static JSBool
+gjs_array_to_ptrarray(JSContext *context,
+ jsval array_value,
+ unsigned int length,
+ GITransfer transfer,
+ GITypeInfo *param_info,
+ void **arr_p)
+{
+ unsigned int i;
+
+ void **array = g_malloc0(length * sizeof(gpointer));
+
+ for (i = 0; i < length; i++) {
+ jsval elem;
+ GIArgument arg;
+ arg.v_pointer = NULL;
+
+ JSBool success;
+
+ elem = JSVAL_VOID;
+ if (!JS_GetElement(context, JSVAL_TO_OBJECT(array_value),
+ i, &elem)) {
+ g_free(array);
+ gjs_throw(context,
+ "Missing array element %u",
+ i);
+ return JS_FALSE;
+ }
+
+ success = gjs_value_to_g_argument (context,
+ elem,
+ param_info,
+ NULL, /* arg name */
+ GJS_ARGUMENT_ARRAY_ELEMENT,
+ transfer,
+ FALSE, /* absent better information, FALSE for now */
+ &arg);
+
+ if (!success) {
+ g_free(array);
+ gjs_throw(context,
+ "Invalid element in array");
+ return JS_FALSE;
+ }
+
+ array[i] = arg.v_pointer;
+ }
+
+ *arr_p = array;
+ return JS_TRUE;
+}
+
+static JSBool
gjs_array_to_array(JSContext *context,
jsval array_value,
unsigned int length,
+ GITransfer transfer,
GITypeInfo *param_info,
void **arr_p)
{
@@ -588,6 +691,14 @@ gjs_array_to_array(JSContext *context,
element_type = g_type_info_get_tag(param_info);
element_type = replace_gtype(element_type);
+ if (element_type == GI_TYPE_TAG_INTERFACE) {
+ GIBaseInfo *interface_info = g_type_info_get_interface (param_info);
+ GIInfoType info_type = g_base_info_get_type (interface_info);
+ if (info_type == GI_INFO_TYPE_ENUM || info_type == GI_INFO_TYPE_FLAGS)
+ element_type = g_enum_info_get_storage_type ((GIEnumInfo*) interface_info);
+ g_base_info_unref (interface_info);
+ }
+
switch (element_type) {
case GI_TYPE_TAG_UTF8:
return gjs_array_to_strv (context, array_value, length, arr_p);
@@ -609,6 +720,25 @@ gjs_array_to_array(JSContext *context,
case GI_TYPE_TAG_INT32:
return gjs_array_to_intarray
(context, array_value, length, arr_p, 4, SIGNED);
+ case GI_TYPE_TAG_FLOAT:
+ return gjs_array_to_floatarray
+ (context, array_value, length, arr_p, FALSE);
+ case GI_TYPE_TAG_DOUBLE:
+ return gjs_array_to_floatarray
+ (context, array_value, length, arr_p, TRUE);
+
+ /* Everything else is a pointer type */
+ case GI_TYPE_TAG_INTERFACE:
+ case GI_TYPE_TAG_ARRAY:
+ case GI_TYPE_TAG_GLIST:
+ case GI_TYPE_TAG_GSLIST:
+ case GI_TYPE_TAG_GHASH:
+ return gjs_array_to_ptrarray(context,
+ array_value,
+ length,
+ transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer,
+ param_info,
+ arr_p);
default:
gjs_throw(context,
"Unhandled array element type %d", element_type);
@@ -658,6 +788,7 @@ gjs_array_to_g_array(JSContext *context,
if (!gjs_array_to_array (context,
array_value,
length,
+ GI_TRANSFER_NOTHING, /* always good for the types we handle */
param_info,
&contents))
return JS_FALSE;
@@ -703,6 +834,8 @@ get_argument_display_name(const char *arg_name,
return g_strdup("List element");
case GJS_ARGUMENT_HASH_ELEMENT:
return g_strdup("Hash element");
+ case GJS_ARGUMENT_ARRAY_ELEMENT:
+ return g_strdup("Array element");
}
g_assert_not_reached ();
@@ -1203,6 +1336,7 @@ gjs_value_to_g_argument(JSContext *context,
if (!gjs_array_to_array (context,
value,
length,
+ transfer,
param_info,
&arg->v_pointer))
wrong = TRUE;
@@ -2369,7 +2503,7 @@ gjs_g_arg_release_internal(JSContext *context,
case GI_TYPE_TAG_FILENAME:
if (transfer == GI_TRANSFER_CONTAINER)
g_free(arg->v_pointer);
- else if (transfer == GI_TRANSFER_EVERYTHING)
+ else if (transfer != TRANSFER_IN_NOTHING)
g_strfreev (arg->v_pointer);
break;
@@ -2407,7 +2541,10 @@ gjs_g_arg_release_internal(JSContext *context,
break;
default:
- g_assert_not_reached ();
+ gjs_throw (context,
+ "Releasing a C array with explicit length, that was nested"
+ "inside another container. This is not supported (and will leak)");
+ failed = JS_TRUE;
}
g_base_info_unref((GIBaseInfo*) param_info);
@@ -2440,7 +2577,7 @@ gjs_g_arg_release_internal(JSContext *context,
case GI_TYPE_TAG_GHASH:
if (transfer == GI_TRANSFER_CONTAINER) {
g_array_free((GArray*) arg->v_pointer, TRUE);
- } else if (transfer == GI_TRANSFER_EVERYTHING) {
+ } else if (transfer != TRANSFER_IN_NOTHING) {
GArray *array = arg->v_pointer;
guint i;
@@ -2449,7 +2586,7 @@ gjs_g_arg_release_internal(JSContext *context,
arg.v_pointer = g_array_index (array, gpointer, i);
gjs_g_argument_release(context,
- GI_TRANSFER_EVERYTHING,
+ transfer,
param_info,
&arg);
}
@@ -2597,5 +2734,42 @@ gjs_g_argument_release_in_arg(JSContext *context,
return JS_TRUE;
}
+JSBool
+gjs_g_argument_release_in_array (JSContext *context,
+ GITransfer transfer,
+ GITypeInfo *type_info,
+ guint length,
+ GArgument *arg)
+{
+ GITypeInfo *param_type;
+ gpointer *array;
+ GArgument elem;
+ guint i;
+ JSBool ret = JS_TRUE;
+ GITypeTag type_tag;
+
+ if (transfer != GI_TRANSFER_NOTHING)
+ return JS_TRUE;
+
+ gjs_debug_marshal(GJS_DEBUG_GFUNCTION,
+ "Releasing GArgument array in param");
+
+ array = arg->v_pointer;
+ param_type = g_type_info_get_param_type (type_info, 0);
+ type_tag = g_type_info_get_tag (param_type);
+ if (type_needs_release (param_type, type_tag)) {
+ for (i = 0; i < length; i++) {
+ elem.v_pointer = array[i];
+ if (!gjs_g_arg_release_internal (context, TRANSFER_IN_NOTHING,
+ param_type, type_tag, &elem)) {
+ ret = JS_FALSE;
+ break;
+ }
+ }
+ }
+
+ g_free (array);
+ return ret;
+}
diff --git a/gi/arg.h b/gi/arg.h
index df473e2..47e7f64 100644
--- a/gi/arg.h
+++ b/gi/arg.h
@@ -38,7 +38,8 @@ typedef enum {
GJS_ARGUMENT_RETURN_VALUE,
GJS_ARGUMENT_FIELD,
GJS_ARGUMENT_LIST_ELEMENT,
- GJS_ARGUMENT_HASH_ELEMENT
+ GJS_ARGUMENT_HASH_ELEMENT,
+ GJS_ARGUMENT_ARRAY_ELEMENT
} GjsArgumentType;
JSBool gjs_value_to_arg (JSContext *context,
@@ -67,6 +68,11 @@ JSBool gjs_g_argument_release (JSContext *context,
GITransfer transfer,
GITypeInfo *type_info,
GArgument *arg);
+JSBool gjs_g_argument_release_in_array (JSContext *context,
+ GITransfer transfer,
+ GITypeInfo *type_info,
+ guint length,
+ GArgument *arg);
JSBool gjs_g_argument_release_in_arg (JSContext *context,
GITransfer transfer,
GITypeInfo *type_info,
diff --git a/gi/function.c b/gi/function.c
index 436a458..133a9fa 100644
--- a/gi/function.c
+++ b/gi/function.c
@@ -707,6 +707,7 @@ release:
if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) {
GArgument *arg;
GITransfer transfer;
+ gint array_length_pos;
if (direction == GI_DIRECTION_IN) {
g_assert_cmpuint(in_args_pos, <, in_args_len);
@@ -722,10 +723,26 @@ release:
*/
transfer = GI_TRANSFER_EVERYTHING;
}
- if (!gjs_g_argument_release_in_arg(context,
- transfer,
- &arg_type_info,
- arg)) {
+ if (g_type_info_get_tag (&arg_type_info) == GI_TYPE_TAG_ARRAY &&
+ (array_length_pos = g_type_info_get_array_length (&arg_type_info)) != -1) {
+ /* Assume that the length passed as an argument was the length of the Array
+ (not necessarily true) */
+
+ if (is_method) /* get_array_length does not consider the instance argument */
+ array_length_pos++;
+
+ guint length = in_arg_cvalues[array_length_pos].v_uint;
+ if (!gjs_g_argument_release_in_array (context,
+ transfer,
+ &arg_type_info,
+ length,
+ arg)) {
+ postinvoke_release_failed = TRUE;
+ }
+ } else if (!gjs_g_argument_release_in_arg(context,
+ transfer,
+ &arg_type_info,
+ arg)) {
postinvoke_release_failed = TRUE;
}
}
diff --git a/test/js/testGIMarshalling.js b/test/js/testGIMarshalling.js
index 467b105..112f1d5 100644
--- a/test/js/testGIMarshalling.js
+++ b/test/js/testGIMarshalling.js
@@ -18,6 +18,20 @@ function testCArray() {
assertEquals(42, array[0].long_);
assertEquals(43, array[1].long_);
assertEquals(44, array[2].long_);
+
+ GIMarshallingTests.array_string_in(["foo", "bar"], 2);
+
+ array = [];
+ for (var i = 0; i < 3; i++) {
+ array[i] = new GIMarshallingTests.BoxedStruct();
+ array[i].long_ = i + 1;
+ }
+
+ GIMarshallingTests.array_struct_in(array, array.length);
+
+ // Run twice to ensure that copies are correctly made for (transfer full)
+ GIMarshallingTests.array_struct_take_in(array, array.length);
+ GIMarshallingTests.array_struct_take_in(array, array.length);
}
function testGArray() {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]