changeset 11176:2271261f088a

Address precision issue in ranges saved to HDF5 files
author David Bateman <dbateman@free.fr>
date Tue, 02 Nov 2010 16:27:30 +0100
parents c0a95a5c6d25
children 30bcd1aa9f09
files src/ChangeLog src/ls-hdf5.cc src/ls-hdf5.h src/ov-range.cc
diffstat 4 files changed, 145 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Tue Nov 02 00:47:31 2010 +0100
+++ b/src/ChangeLog	Tue Nov 02 16:27:30 2010 +0100
@@ -1,3 +1,22 @@
+2010-11-02  David Bateman  <dbateman@free.fr>
+
+	* ls-hdf5.cc (bool hdf5_get_scalar_attr (hid_t, hid_t,
+        const char *, void *), herr_t hdf5_add_scalar_attr
+	(hid_t, hid_t, const char *, void *)): New functions.
+	(herr_t hdf5_add_scalar_attr (hid_t, const char *)): Remove static
+	definition to make this function visible externally.
+	* ls-hdf5.h (extern OCTINTERP_API bool hdf5_check_attr (hid_t,
+	const char *), extern OCTINTERP_API bool hdf5_get_scalar_attr
+	(hid_t, hid_t, const char *, void *buf), extern OCTINTERP_API herr_t
+	hdf5_add_attr (hid_t, const char *), extern OCTINTERP_API herr_t
+	hdf5_add_scalar_attr (hid_t, hid_t, const char *, void *)): Function
+	declarations.
+	* ov-range.cc (bool octave_range::save_hdf5 (hid_t, const char *,
+        bool)): Save the number of elements in the range as an HDF5 attribute.
+	(bool octave_range::load_hdf5 (hid_t, const char *)): If an HDF5
+	attribute containing the number of elements exists use it to ensure
+	the correct number of elements in the range.
+
 2010-11-01  David Bateman  <dbateman@free.fr>
 
 	* gl-render.cc (void opengl_renderer::draw_patch (const
--- a/src/ls-hdf5.cc	Tue Nov 02 00:47:31 2010 +0100
+++ b/src/ls-hdf5.cc	Tue Nov 02 16:27:30 2010 +0100
@@ -156,7 +156,7 @@
   if (attr_id >= 0)
     {
       // successful
-      retval = 1;
+      retval = true;
       H5Aclose (attr_id);
     }
 
@@ -169,6 +169,55 @@
   return retval;
 }
 
+bool
+hdf5_get_scalar_attr (hid_t loc_id, hid_t type_id, 
+                      const char *attr_name, void *buf)
+{
+  bool retval = false;
+
+  // we have to pull some shenanigans here to make sure
+  // HDF5 doesn't print out all sorts of error messages if we
+  // call H5Aopen for a non-existing attribute
+
+  H5E_auto_t err_func;
+  void *err_func_data;
+
+  // turn off error reporting temporarily, but save the error
+  // reporting function:
+
+#if HAVE_HDF5_18
+  H5Eget_auto (H5E_DEFAULT, &err_func, &err_func_data);
+  H5Eset_auto (H5E_DEFAULT, 0, 0);
+#else
+  H5Eget_auto (&err_func, &err_func_data);
+  H5Eset_auto (0, 0);
+#endif
+
+  hid_t attr_id = H5Aopen_name (loc_id, attr_name);
+
+  if (attr_id >= 0)
+    {
+      hid_t space_id = H5Aget_space (attr_id);
+
+      hsize_t rank = H5Sget_simple_extent_ndims (space_id);
+
+      if (rank == 0)
+        retval = H5Aread (attr_id, type_id, buf) >= 0;
+      H5Aclose (attr_id);
+    }
+
+  // restore error reporting:
+#if HAVE_HDF5_18
+  H5Eset_auto (H5E_DEFAULT, err_func, err_func_data);
+#else
+  H5Eset_auto (err_func, err_func_data);
+#endif
+  return retval;
+}
+
+
+
+
 // The following subroutines creates an HDF5 representations of the way
 // we will store Octave complex types (pairs of floating-point numbers).
 // NUM_TYPE is the HDF5 numeric type to use for storage (e.g. 
@@ -576,7 +625,7 @@
 
 // Add an attribute named attr_name to loc_id (a simple scalar
 // attribute with value 1).  Return value is >= 0 on success.
-static herr_t
+herr_t
 hdf5_add_attr (hid_t loc_id, const char *attr_name)
 {
   herr_t retval = 0;
@@ -611,6 +660,46 @@
   return retval;
 }
 
+herr_t
+hdf5_add_scalar_attr (hid_t loc_id, hid_t type_id,
+                      const char *attr_name, void *buf)
+{
+  herr_t retval = 0;
+
+  hid_t as_id = H5Screate (H5S_SCALAR);
+
+  if (as_id >= 0)
+    {
+#if HAVE_HDF5_18
+      hid_t a_id = H5Acreate (loc_id, attr_name, H5T_NATIVE_UCHAR, 
+                              as_id, H5P_DEFAULT, H5P_DEFAULT);
+#else
+      hid_t a_id = H5Acreate (loc_id, attr_name,
+                              H5T_NATIVE_UCHAR, as_id, H5P_DEFAULT);
+#endif
+      if (a_id >= 0)
+        {
+          retval = H5Awrite (a_id, type_id, buf);
+
+          H5Aclose (a_id);
+        }
+      else
+        retval = a_id;
+
+      H5Sclose (as_id);
+    }
+  else
+    retval = as_id;
+
+  return retval;
+}
+
+
+
+
+
+
+
 // Save an empty matrix, if needed. Returns
 //    > 0  Saved empty matrix
 //    = 0  Not an empty matrix; did nothing
--- a/src/ls-hdf5.h	Tue Nov 02 00:47:31 2010 +0100
+++ b/src/ls-hdf5.h	Tue Nov 02 16:27:30 2010 +0100
@@ -186,6 +186,21 @@
                 const std::string& name, const std::string& doc,
                 bool mark_as_global, bool save_as_floats);
 
+extern OCTINTERP_API bool
+hdf5_check_attr (hid_t loc_id, const char *attr_name);
+
+extern OCTINTERP_API bool
+hdf5_get_scalar_attr (hid_t loc_id, hid_t type_id, const char *attr_name,
+                      void *buf);
+
+extern OCTINTERP_API herr_t
+hdf5_add_attr (hid_t loc_id, const char *attr_name);
+
+
+extern OCTINTERP_API herr_t
+hdf5_add_scalar_attr (hid_t loc_id, hid_t type_id, 
+                      const char *attr_name, void *buf);
+
 #ifdef IDX_TYPE_LONG
 #define H5T_NATIVE_IDX H5T_NATIVE_LONG
 #else
--- a/src/ov-range.cc	Tue Nov 02 00:47:31 2010 +0100
+++ b/src/ov-range.cc	Tue Nov 02 16:27:30 2010 +0100
@@ -548,8 +548,15 @@
   range_vals[1] = r.inc () != 0 ? r.limit () : r.nelem ();
   range_vals[2] = r.inc ();
 
-  retval = H5Dwrite (data_hid, type_hid, H5S_ALL, H5S_ALL, H5P_DEFAULT,
-                     range_vals) >= 0;
+  if (H5Dwrite (data_hid, type_hid, H5S_ALL, H5S_ALL, H5P_DEFAULT,
+                range_vals) >= 0)
+    {
+      octave_idx_type nel = r.nelem ();
+      retval = hdf5_add_scalar_attr (data_hid, H5T_NATIVE_IDX,
+                                     "OCTAVE_RANGE_NELEM", &nel) >= 0;
+    }
+  else
+    retval = false;
 
   H5Dclose (data_hid);
   H5Tclose (type_hid);
@@ -595,11 +602,18 @@
                rangevals) >= 0)
     {
       retval = true;
-      if (rangevals[2] != 0)
-        range = Range (rangevals[0], rangevals[1], rangevals[2]);
+      octave_idx_type nel;
+      if (hdf5_get_scalar_attr (data_hid, H5T_NATIVE_IDX, 
+                                "OCTAVE_RANGE_NELEM", &nel))
+        range = Range (rangevals[0], rangevals[2], nel);
       else
-        range = Range (rangevals[0], rangevals[2], 
-                       static_cast<octave_idx_type> (rangevals[1]));
+        {
+          if (rangevals[2] != 0)
+            range = Range (rangevals[0], rangevals[1], rangevals[2]);
+          else
+            range = Range (rangevals[0], rangevals[2], 
+                           static_cast<octave_idx_type> (rangevals[1]));
+        }
     }
 
   H5Tclose (range_type);