]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
Added support for direct generics wip/direct-generics 0c53c5ec3a5f464febca4d82a257afa98241ba01 52/head
authorJakub Kaszycki <jakub@kaszycki.net.pl>
Thu, 7 Mar 2019 19:32:22 +0000 (20:32 +0100)
committerRico Tzschichholz <ricotz@ubuntu.com>
Fri, 22 Mar 2019 21:51:40 +0000 (22:51 +0100)
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
tests/basic-types/garray.vala
vala/valausedattr.vala
vapi/glib-2.0.vapi

index 7b34ec7af8cfbd9f5464beaf056208e264520f04..5ea3028246de00b437dea77fb01776e17b030be8 100644 (file)
@@ -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);
                                        }
index 2d2eb008d2a7c32873cc6494be9e96b434be72ea..636d8857f246489adc448b88564adc081398f17c 100644 (file)
@@ -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 ();
 }
index c4c05cdaaf6ee414e14b79e3f893edd26c2dbf04..00c4fba6bdf20bb2bfb2ab01811f835b6afd4cff 100644 (file)
@@ -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", "",
index 15a62a1961807ec7d942f4f2e1d17ed3d195682f..f84bd1a5bca82f8499a3cb5193fd6adf47cadcbf 100644 (file)
@@ -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;