[gobject-introspection] scanner: Flatten multi-dimensional arrays fields



commit d020c524bad9a9e26b124b85a356d3858b03cab7
Author: Tomasz Miąsko <tomasz miasko gmail com>
Date:   Mon Jan 7 00:00:00 2019 +0000

    scanner: Flatten multi-dimensional arrays fields
    
    Provide partial support for multi-dimensional arrays by representing
    them as flattened one dimensional array with size that is equal to
    product of sizes in each dimension. Previously only the first dimension
    would be actually used.
    
    This should be sufficient to ensure that those fields have layout
    compatible with C, without using nested array types that are currently
    unsupported by vapigen
    
    Issue #255.

 giscanner/transformer.py          | 27 +++++++++++++++----------
 tests/offsets/gitestoffsets.c     | 11 ++++++++++
 tests/offsets/offsets.h           | 15 ++++++++++++++
 tests/scanner/test_transformer.py | 42 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 85 insertions(+), 10 deletions(-)
---
diff --git a/giscanner/transformer.py b/giscanner/transformer.py
index e2294a63..9911de70 100644
--- a/giscanner/transformer.py
+++ b/giscanner/transformer.py
@@ -551,25 +551,32 @@ raise ValueError."""
             # Special handling for fields; we don't have annotations on them
             # to apply later, yet.
             if source_type.type == CTYPE_ARRAY:
+                # Determine flattened array size and its element type.
+                flattened_size = 1
+                while source_type.type == CTYPE_ARRAY:
+                    for child in source_type.child_list:
+                        if flattened_size is not None:
+                            flattened_size *= child.const_int
+                        break
+                    else:
+                        flattened_size = None
+                    source_type = source_type.base_type
+
                 # If the array contains anonymous unions, like in the GValue
                 # struct, we need to handle this specially.  This is necessary
                 # to be able to properly calculate the size of the compound
                 # type (e.g. GValue) that contains this array, see
                 # <https://bugzilla.gnome.org/show_bug.cgi?id=657040>.
-                if (source_type.base_type.type == CTYPE_UNION
-                and source_type.base_type.name is None):
-                    synthesized_type = self._synthesize_union_type(symbol, parent_symbol)
-                    ftype = ast.Array(None, synthesized_type)
+                if source_type.type == CTYPE_UNION and source_type.name is None:
+                    element_type = self._synthesize_union_type(symbol, parent_symbol)
                 else:
                     ctype = self._create_source_type(source_type)
                     complete_ctype = self._create_complete_source_type(source_type)
-                    from_ctype = self.create_type_from_ctype_string(ctype,
-                                                                    complete_ctype=complete_ctype)
-                    ftype = ast.Array(None, from_ctype)
-                child_list = list(symbol.base_type.child_list)
+                    element_type = self.create_type_from_ctype_string(ctype,
+                                                                      complete_ctype=complete_ctype)
+                ftype = ast.Array(None, element_type)
                 ftype.zeroterminated = False
-                if child_list:
-                    ftype.size = child_list[0].const_int
+                ftype.size = flattened_size
             else:
                 ftype = self._create_type_from_base(symbol.base_type)
             # ast.Fields are assumed to be read-write
diff --git a/tests/offsets/gitestoffsets.c b/tests/offsets/gitestoffsets.c
index 9ce673e9..a84e8e8a 100644
--- a/tests/offsets/gitestoffsets.c
+++ b/tests/offsets/gitestoffsets.c
@@ -92,6 +92,16 @@ compiled (FILE *outfile)
   PRINT_MEMBER (OffsetsArray, some_ptrs);
   g_fprintf (outfile, "\n");
 
+  PRINT_TYPE (OffsetsMultiDimArray);
+  PRINT_MEMBER (OffsetsMultiDimArray, ints);
+  PRINT_MEMBER (OffsetsMultiDimArray, chars);
+  PRINT_MEMBER (OffsetsMultiDimArray, floats);
+  PRINT_MEMBER (OffsetsMultiDimArray, pointers1);
+  PRINT_MEMBER (OffsetsMultiDimArray, pointers2);
+  PRINT_MEMBER (OffsetsMultiDimArray, pointers3);
+  PRINT_MEMBER (OffsetsMultiDimArray, dummy);
+  fprintf (outfile, "\n");
+
   PRINT_TYPE (OffsetsBasic);
   PRINT_MEMBER (OffsetsBasic, dummy1);
   PRINT_MEMBER (OffsetsBasic, field_int8);
@@ -183,6 +193,7 @@ int main(int argc, char **argv)
     g_error ("Cannot open '%s': %s'", argv[1], g_strerror(errno));
 
   introspected_struct (outfile, "Array");
+  introspected_struct (outfile, "MultiDimArray");
   introspected_struct (outfile, "Basic");
   introspected_struct (outfile, "Enum");
   introspected_struct (outfile, "Nested");
diff --git a/tests/offsets/offsets.h b/tests/offsets/offsets.h
index 658601f5..7d89fe8d 100644
--- a/tests/offsets/offsets.h
+++ b/tests/offsets/offsets.h
@@ -124,6 +124,21 @@ struct _OffsetsArray
   gpointer some_ptrs[5];
 };
 
+/* Test multi-dimensional arrays */
+
+typedef struct _OffsetsMultiDimArray OffsetsMultiDimArray;
+
+struct _OffsetsMultiDimArray
+{
+  gint ints[10][2];
+  gchar chars[255][10];
+  float floats[11][13][17];
+  gchar* pointers1[3][5];
+  gpointer pointers2[7][9];
+  double** pointers3[2][3][4];
+  gchar dummy;
+};
+
 /* Test object offsets */
 
 typedef struct _OffsetsObj OffsetsObj;
diff --git a/tests/scanner/test_transformer.py b/tests/scanner/test_transformer.py
index 4731b5ce..92f21c67 100644
--- a/tests/scanner/test_transformer.py
+++ b/tests/scanner/test_transformer.py
@@ -483,5 +483,47 @@ class TestCallbacks(unittest.TestCase):
         self.assertTrue(isinstance(node, ast.Callback))
 
 
+class TestArrays(unittest.TestCase):
+    def setUp(self):
+        # Hack to set logging singleton
+        self.namespace = ast.Namespace('Test', '1.0')
+        logger = MessageLogger.get(namespace=self.namespace)
+        logger.enable_warnings((WARNING, ERROR, FATAL))
+
+    def test_multidimensional_arrays(self):
+        """Multidimensional arrays are flattend into a single dimension."""
+
+        load_namespace_from_source_string(self.namespace, """
+            typedef struct {
+              int data[2][3][5][7][11];
+            } TestMultiDimArray;
+            """)
+
+        node = self.namespace.get('MultiDimArray')
+        self.assertIsNotNone(node)
+
+        field = node.fields[0]
+        self.assertIsInstance(field, ast.Field)
+        self.assertIsInstance(field.type, ast.Array)
+        self.assertEqual(field.type.element_type, ast.TYPE_INT)
+        self.assertEqual(field.type.size, 2 * 3 * 5 * 7 * 11)
+
+    def test_flexible_array_member(self):
+        """Flexible array members don't break transformer.
+
+        They are generally unsupported, so nothing else is validated.
+        """
+
+        load_namespace_from_source_string(self.namespace, """
+            typedef struct {
+              int length;
+              unsigned char data[];
+            } TestFlexibleArray;
+            """)
+
+        node = self.namespace.get('FlexibleArray')
+        self.assertIsNotNone(node)
+
+
 if __name__ == '__main__':
     unittest.main()


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]