summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Kaszycki <jakub@kaszycki.net.pl>2019-03-07 20:32:22 +0100
committerRico Tzschichholz <ricotz@ubuntu.com>2019-03-22 22:51:40 +0100
commit0c53c5ec3a5f464febca4d82a257afa98241ba01 (patch)
tree28fbfcaf3b405103e02c9d11be80b9a4e4d21176
parentf83ecd81d6ede886e1d2573c60da28b993db89e3 (diff)
downloadvala-wip/direct-generics.tar.gz
Added support for direct genericswip/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.
-rw-r--r--codegen/valaccodebasemodule.vala24
-rw-r--r--tests/basic-types/garray.vala67
-rw-r--r--vala/valausedattr.vala3
-rw-r--r--vapi/glib-2.0.vapi2
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;