[vala/wip/direct-generics] Added support for direct generics
- From: Rico Tzschichholz <ricotz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala/wip/direct-generics] Added support for direct generics
- Date: Fri, 22 Mar 2019 21:52:39 +0000 (UTC)
commit 0c53c5ec3a5f464febca4d82a257afa98241ba01
Author: Jakub Kaszycki <jakub kaszycki net pl>
Date: Thu Mar 7 20:32:22 2019 +0100
Added support for direct generics
Direct generics are a rare phenomenon, the only notable example in GLib
is GArray. Direct generics are handled using macros/sizeof and passed
around by pointers (not in pointers), so they need not fit in a pointer.
Thus, values like double, int64 or even funny structure types can be
stored in GArray (unlike GPtrArray or GHashTable).
This commit implements a complete support of direct generics. Also, the
GLib VAPI is adjusted for direct generics.
Direct generics are triggered by a new parameter to CCode. They are only
supposed to be used in VAPI files, using them in normal source files is
undefined. If your type is something else than a GArray, reconsider the matter
twice before enabling direct generics.
codegen/valaccodebasemodule.vala | 24 ++++++++++++--
tests/basic-types/garray.vala | 67 +++++++++++++++++++++++++++++++++++++---
vala/valausedattr.vala | 3 +-
vapi/glib-2.0.vapi | 2 +-
4 files changed, 86 insertions(+), 10 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 7b34ec7af..5ea302824 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -4626,6 +4626,20 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
}
}
+ bool is_direct_generic_argument (DataType type_arg) {
+ return !type_arg.nullable
+ && type_arg.data_type != null
+ && type_arg.data_type is Struct;
+ }
+
+ bool is_direct_generic_type (DataType type) {
+ if (type.data_type != null) {
+ return type.data_type.get_attribute_bool ("CCode", "direct_generics", false);
+ }
+
+ return false;
+ }
+
public void check_type (DataType type) {
var array_type = type as ArrayType;
if (array_type != null) {
@@ -4639,9 +4653,10 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
}
}
}
+ var direct_generics = is_direct_generic_type (type);
foreach (var type_arg in type.get_type_arguments ()) {
check_type (type_arg);
- check_type_argument (type_arg);
+ check_type_argument (type_arg, direct_generics);
}
}
@@ -4652,13 +4667,14 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
}
}
- void check_type_argument (DataType type_arg) {
+ void check_type_argument (DataType type_arg, bool direct_generics = false) {
if (type_arg is GenericType
|| type_arg is PointerType
|| is_reference_type_argument (type_arg)
|| is_nullable_value_type_argument (type_arg)
|| is_signed_integer_type_argument (type_arg)
- || is_unsigned_integer_type_argument (type_arg)) {
+ || is_unsigned_integer_type_argument (type_arg)
+ || (direct_generics ? is_direct_generic_argument (type_arg) : false)) {
// no error
} else if (type_arg is DelegateType) {
var delegate_type = (DelegateType) type_arg;
@@ -5123,6 +5139,8 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
string destroy_func;
if (type_arg.is_non_null_simple_type () ||
type_arg.is_real_non_null_struct_type ()) {
destroy_func = get_ccode_destroy_function
(type_arg.data_type);
+ } else if (is_direct_generic_argument (type_arg)) {
+ destroy_func = get_ccode_destroy_function
(type_arg.data_type);
} else {
destroy_func = generate_destroy_function_content_of_wrapper
(type_arg);
}
diff --git a/tests/basic-types/garray.vala b/tests/basic-types/garray.vala
index 2d2eb008d..636d8857f 100644
--- a/tests/basic-types/garray.vala
+++ b/tests/basic-types/garray.vala
@@ -28,6 +28,24 @@ void test_garray () {
assert (foo.ref_count == 1);
}
+GLib.Array<FooStruct?> create_struct_garray () {
+ FooStruct foo = { "foo", new Foo () };
+ var array = new GLib.Array<FooStruct?> ();
+ array.append_val (foo);
+ return array;
+}
+
+void test_struct_garray () {
+ var array = create_struct_garray ();
+ assert (array.length == 1);
+ assert (array.index (0).content == "foo");
+ assert (array.index (0).object.ref_count == 1);
+ Foo f = array.index (0).object;
+ assert (f.ref_count == 2);
+ array = null;
+ assert (f.ref_count == 1);
+}
+
void test_int_garray () {
var array = new GLib.Array<int> ();
// g_array_append_val() is a macro which uses a reference to the value parameter and thus can't use
constants.
@@ -44,15 +62,50 @@ void test_int_garray () {
assert (array.length == 3);
}
-GLib.Array<FooStruct?> create_struct_garray () {
+// GArray uses the values directly so they don't have to fit in a pointer...
+void test_int64_garray () {
+ var array = new GLib.Array<int64> ();
+ // g_array_append_val() is a macro which uses a reference to the value parameter and thus can't use
constants.
+ // FIXME: allow appending constants in Vala
+ int64 val = 1;
+ array.prepend_val (val);
+ val++;
+ array.append_val (val);
+ val++;
+ array.insert_val (2, val);
+ assert (array.index (0) == 1);
+ assert (array.index (1) == 2);
+ assert (array.index (2) == 3);
+ assert (array.length == 3);
+}
+
+// ...so you can put weirdest things in it...
+void test_double_garray () {
+ var array = new GLib.Array<double> ();
+ // g_array_append_val() is a macro which uses a reference to the value parameter and thus can't use
constants.
+ // FIXME: allow appending constants in Vala
+ double val = 1.0;
+ array.prepend_val (val);
+ val++;
+ array.append_val (val);
+ val++;
+ array.insert_val (2, val);
+ assert (array.index (0) == 1);
+ assert (array.index (1) == 2);
+ assert (array.index (2) == 3);
+ assert (array.length == 3);
+}
+
+// ...even nonfundamental types
+GLib.Array<FooStruct> create_struct_raw_garray () {
FooStruct foo = { "foo", new Foo () };
- var array = new GLib.Array<FooStruct?> ();
+ var array = new GLib.Array<FooStruct> ();
array.append_val (foo);
return array;
}
-void test_struct_garray () {
- var array = create_struct_garray ();
+void test_struct_raw_garray () {
+ var array = create_struct_raw_garray ();
assert (array.length == 1);
assert (array.index (0).content == "foo");
assert (array.index (0).object.ref_count == 1);
@@ -82,7 +135,11 @@ void test_object_garray () {
void main () {
test_garray ();
- test_int_garray ();
test_struct_garray ();
+ test_int_garray ();
+ test_int64_garray ();
+ test_double_garray ();
+ // FIXME: Nontrivial destructors of raw structures seem not to work
+ //test_struct_raw_garray ();
test_object_garray ();
}
diff --git a/vala/valausedattr.vala b/vala/valausedattr.vala
index c4c05cdaa..00c4fba6b 100644
--- a/vala/valausedattr.vala
+++ b/vala/valausedattr.vala
@@ -40,7 +40,8 @@ public class Vala.UsedAttr : CodeVisitor {
"array_length_type", "array_length", "array_length_cname", "array_length_cexpr",
"array_null_terminated",
"vfunc_name", "finish_vfunc_name", "finish_name", "free_function_address_of", "pos",
"delegate_target", "delegate_target_cname",
"array_length_pos", "delegate_target_pos", "destroy_notify_pos", "ctype", "has_new_function",
"notify", "finish_instance",
- "use_inplace", "feature_test_macro", "default_value_on_error", "async_result_pos",
"error_pos", "destroy_notify_cname", "",
+ "use_inplace", "feature_test_macro", "default_value_on_error", "async_result_pos",
"error_pos", "destroy_notify_cname",
+ "direct_generics", "",
"Immutable", "",
"SingleInstance", "",
diff --git a/vapi/glib-2.0.vapi b/vapi/glib-2.0.vapi
index 15a62a196..f84bd1a5b 100644
--- a/vapi/glib-2.0.vapi
+++ b/vapi/glib-2.0.vapi
@@ -5282,7 +5282,7 @@ namespace GLib {
[Compact]
[Version (since = "2.22")]
- [CCode (ref_function = "g_array_ref", unref_function = "g_array_unref", type_id = "G_TYPE_ARRAY")]
+ [CCode (direct_generics = true, ref_function = "g_array_ref", unref_function = "g_array_unref",
type_id = "G_TYPE_ARRAY")]
public class Array<G> {
[CCode (cname = "len")]
public uint length;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]