diff options
author | Jakub Kaszycki <jakub@kaszycki.net.pl> | 2019-03-07 20:32:22 +0100 |
---|---|---|
committer | Rico Tzschichholz <ricotz@ubuntu.com> | 2019-03-22 22:51:40 +0100 |
commit | 0c53c5ec3a5f464febca4d82a257afa98241ba01 (patch) | |
tree | 28fbfcaf3b405103e02c9d11be80b9a4e4d21176 | |
parent | f83ecd81d6ede886e1d2573c60da28b993db89e3 (diff) | |
download | vala-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.vala | 24 | ||||
-rw-r--r-- | tests/basic-types/garray.vala | 67 | ||||
-rw-r--r-- | vala/valausedattr.vala | 3 | ||||
-rw-r--r-- | 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; |