diff libinterp/corefcn/jsondecode.cc @ 29994:eb768fc5e6b7

jsondecode.cc: Handle array of arrays and arrays of structs correctly (bug #60688) * libinterp/corefcn/jsondecode.cc (decode_object_array): Resize struct array if it has no fields. * libinterp/corefcn/jsondecode.cc (decode_array_of_arrays): Handle struct arrays correctly. * test/json/jsondecode_BIST.tst: New tests. Many thanks to an anonymous contributor.
author Kai T. Ohlhus <k.ohlhus@gmail.com>
date Wed, 18 Aug 2021 14:56:07 +0900
parents c7c69808356f
children 4628ae890642
line wrap: on
line diff
--- a/libinterp/corefcn/jsondecode.cc	Wed Aug 18 00:25:50 2021 -0400
+++ b/libinterp/corefcn/jsondecode.cc	Wed Aug 18 14:56:07 2021 +0900
@@ -239,13 +239,22 @@
   if (same_field_names)
     {
       octave_map struct_array;
-      Cell value (dim_vector (struct_cell.numel (), 1));
-      for (octave_idx_type i = 0; i < field_names.numel (); ++i)
+      dim_vector struct_array_dims = dim_vector (struct_cell.numel (), 1);
+
+      if (field_names.numel ())
         {
-          for (octave_idx_type k = 0; k < struct_cell.numel (); ++k)
-            value(k) = struct_cell(k).scalar_map_value ().getfield (field_names(i));
-          struct_array.assign (field_names(i), value);
+          Cell value (struct_array_dims);
+          for (octave_idx_type i = 0; i < field_names.numel (); ++i)
+            {
+              for (octave_idx_type k = 0; k < struct_cell.numel (); ++k)
+                value(k) = struct_cell(k).scalar_map_value ()
+                                         .getfield (field_names(i));
+              struct_array.assign (field_names(i), value);
+            }
         }
+      else
+        struct_array.resize (struct_array_dims, true);
+
       return struct_array;
     }
   else
@@ -286,6 +295,9 @@
 
   // Only arrays with sub-arrays of booleans and numericals will return NDArray
   bool is_bool = cell(0).is_bool_matrix ();
+  bool is_struct = cell(0).isstruct ();
+  string_vector field_names = is_struct ? cell(0).map_value ().fieldnames ()
+                                        : string_vector ();
   dim_vector sub_array_dims = cell(0).dims ();
   octave_idx_type sub_array_ndims = cell(0).ndims ();
   octave_idx_type cell_numel = cell.numel ();
@@ -302,6 +314,13 @@
       // return cell array
       if (cell(i).is_bool_matrix () != is_bool)
         return cell;
+      // If not struct arrays only, return cell array
+      if (cell(i).isstruct () != is_struct)
+        return cell;
+      // If struct arrays have different fields, return cell array
+      if (is_struct && (field_names.std_list ()
+                        != cell(i).map_value ().fieldnames ().std_list ()))
+        return cell;
     }
 
   // Calculate the dims of the output array
@@ -310,21 +329,55 @@
   array_dims(0) = cell_numel;
   for (auto i = 1; i < sub_array_ndims + 1; i++)
     array_dims(i) = sub_array_dims(i-1);
-  NDArray array (array_dims);
 
-  // Populate the array with specific order to generate MATLAB-identical output
-  octave_idx_type sub_array_numel = array.numel () / cell_numel;
-  for (octave_idx_type k = 0; k < cell_numel; ++k)
+  if (is_struct)
     {
-      NDArray sub_array_value = cell(k).array_value ();
-      for (octave_idx_type i = 0; i < sub_array_numel; ++i)
-        array(k + i*cell_numel) = sub_array_value(i);
-    }
+      octave_map struct_array;
+      array_dims.chop_trailing_singletons ();
+
+      if (field_names.numel ())
+        {
+          Cell value (array_dims);
+          octave_idx_type sub_array_numel = sub_array_dims.numel ();
 
-  if (is_bool)
-    return boolNDArray (array);
+          for (octave_idx_type j = 0; j < field_names.numel (); ++j)
+            {
+              // Populate the array with specific order to generate
+              // MATLAB-identical output.
+              for (octave_idx_type k = 0; k < cell_numel; ++k)
+                {
+                  Cell sub_array_value = cell(k).map_value ()
+                                                .getfield (field_names(j));
+                  for (octave_idx_type i = 0; i < sub_array_numel; ++i)
+                    value(k + i * cell_numel) = sub_array_value(i);
+                }
+              struct_array.assign (field_names(j), value);
+            }
+        }
+      else
+        struct_array.resize(array_dims, true);
+
+      return struct_array;
+    }
   else
-    return array;
+    {
+      NDArray array (array_dims);
+
+      // Populate the array with specific order to generate MATLAB-identical
+      // output.
+      octave_idx_type sub_array_numel = array.numel () / cell_numel;
+      for (octave_idx_type k = 0; k < cell_numel; ++k)
+        {
+          NDArray sub_array_value = cell(k).array_value ();
+          for (octave_idx_type i = 0; i < sub_array_numel; ++i)
+            array(k + i * cell_numel) = sub_array_value(i);
+        }
+
+      if (is_bool)
+        return boolNDArray (array);
+      else
+        return array;
+    }
 }
 
 //! Decodes any type of JSON arrays.  This function only serves as an interface