[vala/wip/direct-generics] Added support for direct generics



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]