Mercurial > hg > octave-nkf
changeset 4687:e95c86d48732
[project @ 2004-01-06 21:53:34 by jwe]
author | jwe |
---|---|
date | Tue, 06 Jan 2004 21:53:34 +0000 |
parents | c7ae43dfdea4 |
children | eaa2caaa35d6 |
files | liboctave/CNDArray.cc liboctave/CNDArray.h liboctave/ChangeLog liboctave/dNDArray.cc liboctave/dNDArray.h src/ChangeLog src/load-save.cc src/load-save.h src/ls-hdf5.cc src/ls-hdf5.h src/ls-oct-ascii.cc src/ls-oct-ascii.h src/ls-oct-binary.cc src/ov-base.cc src/ov-base.h src/ov-bool-mat.cc src/ov-bool-mat.h src/ov-bool.cc src/ov-bool.h src/ov-cell.cc src/ov-cell.h src/ov-complex.cc src/ov-complex.h src/ov-cx-mat.cc src/ov-cx-mat.h src/ov-list.cc src/ov-list.h src/ov-range.cc src/ov-range.h src/ov-re-mat.cc src/ov-re-mat.h src/ov-scalar.cc src/ov-scalar.h src/ov-str-mat.cc src/ov-str-mat.h src/ov-struct.cc src/ov-struct.h src/ov-typeinfo.cc src/ov.h |
diffstat | 39 files changed, 3855 insertions(+), 1531 deletions(-) [+] |
line wrap: on
line diff
--- a/liboctave/CNDArray.cc +++ b/liboctave/CNDArray.cc @@ -29,10 +29,13 @@ #include <config.h> #endif +#include <cfloat> + #include "Array-util.h" #include "CNDArray.h" #include "mx-base.h" #include "lo-ieee.h" +#include "lo-mappers.h" // XXX FIXME XXX -- could we use a templated mixed-type copy function // here? @@ -73,6 +76,114 @@ // XXX FIXME XXX -- this is not quite the right thing. +bool +ComplexNDArray::any_element_is_inf_or_nan (void) const +{ + int nel = nelem (); + + for (int i = 0; i < nel; i++) + { + Complex val = elem (i); + if (xisinf (val) || xisnan (val)) + return true; + } + return false; +} + +// Return true if no elements have imaginary components. + +bool +ComplexNDArray::all_elements_are_real (void) const +{ + int nel = nelem (); + + for (int i = 0; i < nel; i++) + { + double ip = imag (elem (i)); + + if (ip != 0.0 || lo_ieee_signbit (ip)) + return false; + } + + return true; +} + +// Return nonzero if any element of CM has a non-integer real or +// imaginary part. Also extract the largest and smallest (real or +// imaginary) values and return them in MAX_VAL and MIN_VAL. + +bool +ComplexNDArray::all_integers (double& max_val, double& min_val) const +{ + int nel = nelem (); + + if (nel > 0) + { + Complex val = elem (0); + + double r_val = real (val); + double i_val = imag (val); + + max_val = r_val; + min_val = r_val; + + if (i_val > max_val) + max_val = i_val; + + if (i_val < max_val) + min_val = i_val; + } + else + return false; + + for (int i = 0; i < nel; i++) + { + Complex val = elem (i); + + double r_val = real (val); + double i_val = imag (val); + + if (r_val > max_val) + max_val = r_val; + + if (i_val > max_val) + max_val = i_val; + + if (r_val < min_val) + min_val = r_val; + + if (i_val < min_val) + min_val = i_val; + + if (D_NINT (r_val) != r_val || D_NINT (i_val) != i_val) + return false; + } + + return true; +} + +bool +ComplexNDArray::too_large_for_float (void) const +{ + int nel = nelem (); + + for (int i = 0; i < nel; i++) + { + Complex val = elem (i); + + double r_val = real (val); + double i_val = imag (val); + + if (r_val > FLT_MAX + || i_val > FLT_MAX + || r_val < FLT_MIN + || i_val < FLT_MIN) + return true; + } + + return false; +} + boolNDArray ComplexNDArray::all (int dim) const { @@ -175,6 +286,47 @@ return ::compute_index (ra_idx, dimensions); } + +// This contains no information on the array structure !!! +std::ostream& +operator << (std::ostream& os, const ComplexNDArray& a) +{ + int nel = a.nelem (); + + for (int i = 0; i < nel; i++) + { + os << " "; + octave_write_complex (os, a.elem (i)); + os << "\n"; + } + return os; +} + +std::istream& +operator >> (std::istream& is, ComplexNDArray& a) +{ + int nel = a.nelem (); + + if (nel < 1 ) + is.clear (std::ios::badbit); + else + { + Complex tmp; + for (int i = 0; i < nel; i++) + { + tmp = octave_read_complex (is); + if (is) + a.elem (i) = tmp; + else + goto done; + } + } + + done: + + return is; +} + NDS_CMP_OPS(ComplexNDArray, real, Complex, real) NDS_BOOL_OPS(ComplexNDArray, Complex, 0.0)
--- a/liboctave/CNDArray.h +++ b/liboctave/CNDArray.h @@ -74,6 +74,11 @@ // XXX FIXME XXX -- this is not quite the right thing. + bool any_element_is_inf_or_nan (void) const; + bool all_elements_are_real (void) const; + bool all_integers (double& max_val, double& min_val) const; + bool too_large_for_float (void) const; + boolNDArray all (int dim = -1) const; boolNDArray any (int dim = -1) const; @@ -98,8 +103,8 @@ // i/o - // friend std::ostream& operator << (std::ostream& os, const NDArray& a); - // friend std::istream& operator >> (std::istream& is, NDArray& a); + friend std::ostream& operator << (std::ostream& os, const ComplexNDArray& a); + friend std::istream& operator >> (std::istream& is, ComplexNDArray& a); static Complex resize_fill_value (void) { return Complex (0.0, 0.0); }
--- a/liboctave/ChangeLog +++ b/liboctave/ChangeLog @@ -1,3 +1,14 @@ +2004-01-06 David Bateman <dbateman@free.fr> + + * CNDArray.cc (ComplexNDArray::any_element_is_inf_or_nan, + ComplexNDArray::all_elements_are_real, ComplexNDArray::all_integers, + ComplexNDArray::too_large_for_float): New functions + + * CNDArray.cc (operator <<, operator >>): New IO operators. + * CNDArray.h: Provide decls. + * dNDArray.cc (operator <<, operator >>): New IO operators. + * dNDArray.h: Provide decls. + 2003-12-10 John W. Eaton <jwe@bevo.che.wisc.edu> * mx-ops: Delete bnda x bnda, b x bnda, and bnda x b ops since
--- a/liboctave/dNDArray.cc +++ b/liboctave/dNDArray.cc @@ -286,6 +286,46 @@ return ::compute_index (ra_idx, dimensions); } +// This contains no information on the array structure !!! +std::ostream& +operator << (std::ostream& os, const NDArray& a) +{ + int nel = a.nelem (); + + for (int i = 0; i < nel; i++) + { + os << " "; + octave_write_double (os, a.elem (i)); + os << "\n"; + } + return os; +} + +std::istream& +operator >> (std::istream& is, NDArray& a) +{ + int nel = a.nelem (); + + if (nel < 1 ) + is.clear (std::ios::badbit); + else + { + double tmp; + for (int i = 0; i < nel; i++) + { + tmp = octave_read_double (is); + if (is) + a.elem (i) = tmp; + else + goto done; + } + } + + done: + + return is; +} + NDS_CMP_OPS(NDArray, , double, ) NDS_BOOL_OPS(NDArray, double, 0.0)
--- a/liboctave/dNDArray.h +++ b/liboctave/dNDArray.h @@ -105,8 +105,8 @@ // i/o - // friend std::ostream& operator << (std::ostream& os, const NDArray& a); - // friend std::istream& operator >> (std::istream& is, NDArray& a); + friend std::ostream& operator << (std::ostream& os, const NDArray& a); + friend std::istream& operator >> (std::istream& is, NDArray& a); static double resize_fill_value (void) { return 0; }
--- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,101 @@ +2004-01-06 David Bateman <dbateman@free.fr> + + * ls-hdf5.cc: Fix handle of old versus new format files. + + * ls-oct-binary.cc: Split the load/save functionality into the types + themselves. Backward compatibility maintained. + + * ov-struct.cc (save_binary, load_binary): + * ov-str-mat.cc (save_binary, load_binary): + * ov-scalar.cc (save_binary, load_binary): + * ov-re-mat.cc (save_binary, load_binary): + * ov-range.cc (save_binary, load_binary): + * ov-list.cc (save_binary, load_binary): + * ov-cx-mat.cc (save_binary, load_binary): + * ov-complex.cc (save_binary, load_binary): + * ov-cell.cc (save_binary, load_binary): + * ov-bool.cc (save_binary, load_binary): + * ov-bool-mat.cc (save_binary, load_binary): + New functions for loading and saving structures in octave binary + format. + + * ov-str-mat.h (save_binary, load_binary): + * ov-scalar.h (save_binary, load_binary): + * ov-re-mat.h (save_binary, load_binary): + * ov-range.h (save_binary, load_binary): + * ov-list.h (save_binary, load_binary): + * ov-cx-mat.h (save_binary, load_binary): + * ov-complex.h (save_binary, load_binary): + * ov-cell.h (save_binary, load_binary): + * ov-bool.h (save_binary, load_binary): + * ov-bool-mat.h (save_binary, load_binary): + * ov-struct.h (save_binary, load_binary): + Provide decls. + + * ov.h (save_binary, load_binary): New virtual functions. + + * ov-base.cc (save_binary, load_binary): New functions, for fallbacks + with error message. + * ov-base.h: Provide decls. + + * load-save.cc: Remove "-import" flag and make it the default. + * load-save.h: Likewise. + + * ls-oct-ascii.cc: Split the load/save functionality into the types + themselves. Save "string" variables with the name "string" rather than + string array. Backward compatiability maintained in ov-cs-mat.cc. + Include new version of extract_keyword that halts if the next value is + invalid rather that searching for the next valid value. + + * ls-oct-ascii.h: Extract_keyword header updated. + Include definition of OCT_RBV and CELL_ELT_TAG, since they are now + used elsewhere. + + * ls-hdf5.cc: Split load/save functionality into the types themselves. + The hdf5 format is changed so that each object is a group with a + dataset "type" being a string with the octave_value type and the + dataset or group "value" containing the value of the data, struct, etc. + This allows extensibility. Backward compatibility is maintained. The + "import" flag is now assumed to always be true and has been removed. + + * ov-struct.cc (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-str-mat.cc (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-scalar.cc (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-re-mat.cc (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-range.cc (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-list.cc (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-cx-mat.cc (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-complex.cc (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-cell.cc (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-bool.cc (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-bool-mat.cc (save_ascii, load_ascii, save_hdf5, load_hdf5): + New functions for loading and saving structures in octave ascii + and hdf5 formatted files. + + * ov-struct.h (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-str-mat.h (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-scalar.h (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-re-mat.h (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-range.h (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-list.h (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-cx-mat.h (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-complex.h (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-cell.h (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-bool.h (save_ascii, load_ascii, save_hdf5, load_hdf5): + * ov-bool-mat.h (save_ascii, load_ascii, save_hdf5, load_hdf5): + Provide decls. + + * ov-typeinfo.cc (octave_value_typeinfo::do_lookup_type): Include + make_unique so that the stored type value is not used for all loaded + variables. + + * ov.h: (save_ascii, load_ascii, save_hdf5 and load_hdf5): + New virtual functions. + + * ov-base.cc (save_ascii, load_ascii, save_hdf5, load_hdf5): + New functions, for fallbacks with error message. + * ov-base.h: Provide decls. + 2003-12-22 John W. Eaton <jwe@bevo.che.wisc.edu> * ov-cx-mat.cc (octave_complex_matrix::assign): RHS arg is N-d.
--- a/src/load-save.cc +++ b/src/load-save.cc @@ -375,7 +375,7 @@ octave_value do_load (std::istream& stream, const std::string& orig_fname, bool force, load_save_format format, oct_mach_info::float_format flt_fmt, - bool list_only, bool swap, bool verbose, bool import, + bool list_only, bool swap, bool verbose, const string_vector& argv, int argv_idx, int argc, int nargout) { octave_value retval; @@ -415,8 +415,7 @@ #ifdef HAVE_HDF5 case LS_HDF5: - name = read_hdf5_data (stream, orig_fname, - global, tc, doc, import); + name = read_hdf5_data (stream, orig_fname, global, tc, doc); break; #endif /* HAVE_HDF5 */ @@ -586,19 +585,15 @@ (HDF5 is a free, portable binary format developed by the National\n\ Center for Supercomputing Applications at the University of Illinois.)\n\ Note that Octave can read HDF5 files not created by itself, but may\n\ -skip some datasets in formats that it cannot support. In particular,\n\ -it will skip datasets of data types that it does not recognize, with\n\ -dimensionality > 2, or with names that aren't valid Octave identifiers\n\ -See, however, the @samp{-import} option to ameliorate this somewhat.\n" +skip some datasets in formats that it cannot support.\n" HAVE_HDF5_HELP_STRING "\n\ @item -import\n\ -Make a stronger attempt to import foreign datasets. Currently, this means\n\ -that for HDF5 files, invalid characters in names are converted to @samp{_},\n\ -and datasets with dimensionality > 2 are imported as lists of matrices (or\n\ -lists of lists of matrices, or ...).\n\ +The @samp{-import} is acceptted but ignored for backward compatiability.\n\ +Octave can now support multi-dimensional HDF data and automatically modifies\n\ +variable names if they are invalid Octave identifiers.\n\ \n\ @end table\n\ @end deffn") @@ -621,7 +616,6 @@ bool force = false; bool list_only = false; bool verbose = false; - bool import = false; int i; for (i = 1; i < argc; i++) @@ -665,7 +659,7 @@ } else if (argv[i] == "-import" || argv[i] == "-i") { - import = true; + warning ("load: -import ignored"); } else break; @@ -700,7 +694,7 @@ // can't fix this using std::cin only. retval = do_load (std::cin, orig_fname, force, format, flt_fmt, - list_only, swap, verbose, import, argv, i, argc, + list_only, swap, verbose, argv, i, argc, nargout); } else @@ -724,7 +718,7 @@ { retval = do_load (hdf5_file, orig_fname, force, format, flt_fmt, list_only, swap, verbose, - import, argv, i, argc, nargout); + argv, i, argc, nargout); hdf5_file.close (); } @@ -768,7 +762,7 @@ } retval = do_load (file, orig_fname, force, format, - flt_fmt, list_only, swap, verbose, import, + flt_fmt, list_only, swap, verbose, argv, i, argc, nargout); file.close (); } @@ -1270,7 +1264,7 @@ #ifdef HAVE_HDF5 if (format == LS_HDF5) - error ("load: cannot write HDF5 format to stdout"); + error ("save: cannot write HDF5 format to stdout"); else #endif /* HAVE_HDF5 */ // don't insert any commands here! the brace below must go @@ -1310,11 +1304,12 @@ { hdf5_ofstream hdf5_file (fname.c_str ()); - if (hdf5_file.file_id >= 0) { - save_vars (argv, i, argc, hdf5_file, save_builtins, format, - save_as_floats, true); + if (hdf5_file.file_id >= 0) + { + save_vars (argv, i, argc, hdf5_file, save_builtins, format, + save_as_floats, true); - hdf5_file.close (); + hdf5_file.close (); } else {
--- a/src/load-save.h +++ b/src/load-save.h @@ -61,7 +61,7 @@ extern octave_value do_load (std::istream& stream, const std::string& orig_fname, bool force, load_save_format format, oct_mach_info::float_format flt_fmt, - bool list_only, bool swap, bool verbose, bool import, + bool list_only, bool swap, bool verbose, const string_vector& argv, int argv_idx, int argc, int nargout); extern void
--- a/src/ls-hdf5.cc +++ b/src/ls-hdf5.cc @@ -73,9 +73,6 @@ #include "ls-utils.h" #include "ls-hdf5.h" -// this is only used for HDF5 import -// try to convert s into a valid identifier, replacing invalid chars with "_": - static std::string make_valid_identifier (const std::string& nm) { @@ -98,25 +95,6 @@ return retval; } -static bool -ident_is_all_digits (const std::string& id) -{ - bool retval = true; - - size_t len = 0; - - for (size_t i = 0; i < len; i++) - { - if (! isdigit (id[i])) - { - retval = false; - break; - } - } - - return retval; -} - // Define this to 1 if/when HDF5 supports automatic conversion between // integer and floating-point binary data: #define HAVE_HDF5_INT2FLOAT_CONVERSIONS 0 @@ -148,110 +126,6 @@ return true; } -// Import a multidimensional (rank >= 3) dataset whose id is data_id, into tc. -// This works by calling itself recursively, building up lists of lists -// of lists ... of 2d matrices. rank and dims are the rank and dimensions -// of the dataset. type_id is the datatype to read into. If it is -// H5T_NATIVE_DOUBLE, we are reading a real matrix. Otherwise, type_id -// is assumed to be a complex type for reading a complex matrix. -// -// Upon entry, we should have curdim = rank - 1, start = an array -// of length rank = all zeros, and count = an array of length rank = -// all ones except for the first two dimensions which equal the corresponding -// entries in dims[]. -// -// Note that we process the dimensions in reverse order, reflecting -// the fact that Octave is uses column-major (Fortran-order) data while -// HDF5 is row-major. This means that the HDF5 file is read -// non-contiguously, but on the other hand means that for a 3d array -// we get a list of xy-plane slices, which seems nice. We could change -// this behavior without much trouble; what is the best thing to do? -// -// Returns a positive value upon success. - -static herr_t -hdf5_import_multidim (hid_t data_id, hid_t space_id, hsize_t rank, - const hsize_t *dims, hsize_t curdim, - hssize_t *start, const hsize_t *count, - hid_t type_id, octave_value &tc) -{ - herr_t retval = 1; - - if (rank < 3 || curdim < 1 || curdim >= rank) - return -1; - - if (curdim == 1) - { - // import 2d dataset for 1st 2 dims directly as a matrix - int nr, nc; // rows and columns - nc = dims[0]; // octave uses column-major & HDF5 uses row-major - nr = dims[1]; - - hid_t mem_space_id = H5Screate_simple (2, dims, 0); - - if (mem_space_id < 0) - return -1; - - if (H5Sselect_all (mem_space_id) < 0) - return -1; - - if (H5Sselect_hyperslab (space_id, H5S_SELECT_SET, - start, 0, count, 0) < 0) - { - H5Sclose (mem_space_id); - return -1; - } - - if (type_id == H5T_NATIVE_DOUBLE) - { - // real matrix - Matrix m (nr, nc); - double *re = m.fortran_vec (); - if (H5Dread (data_id, type_id, mem_space_id, space_id, - H5P_DEFAULT, (void *) re) < 0) - retval = -1; // error - else - tc = m; - } - else - { - // assume that we are using complex numbers - // complex matrix - ComplexMatrix m (nr, nc); - Complex *reim = m.fortran_vec (); - if (H5Dread (data_id, type_id, mem_space_id, space_id, - H5P_DEFAULT, (void *) X_CAST (double *, reim)) < 0) - retval = -1; // error - else - tc = m; - } - - H5Sclose (mem_space_id); - - } - else - { - octave_value_list lst; - - for (hsize_t i = 0; i < dims[curdim]; ++i) - { - octave_value slice; - start[curdim] = i; - retval = hdf5_import_multidim (data_id, space_id, rank, - dims, curdim-1, start, count, - type_id, slice); - if (retval < 0) - break; - lst.append (slice); - } - - if (retval > 0) - tc = octave_value (lst); - } - - return retval; -} - // Return true if loc_id has the attribute named attr_name, and false // otherwise. @@ -288,13 +162,13 @@ return retval; } -// The following two subroutines create HDF5 representations of the way -// we will store Octave complex and range types (pairs and triplets of -// floating-point numbers, respectively). NUM_TYPE is the HDF5 numeric -// type to use for storage (e.g. H5T_NATIVE_DOUBLE to save as 'double'). -// Note that any necessary conversions are handled automatically by HDF5. +// 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. +// H5T_NATIVE_DOUBLE to save as 'double'). Note that any necessary +// conversions are handled automatically by HDF5. -static hid_t +hid_t hdf5_make_complex_type (hid_t num_type) { hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 2); @@ -305,52 +179,6 @@ return type_id; } -static hid_t -hdf5_make_range_type (hid_t num_type) -{ - hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 3); - - H5Tinsert (type_id, "base", 0 * sizeof (double), num_type); - H5Tinsert (type_id, "limit", 1 * sizeof (double), num_type); - H5Tinsert (type_id, "increment", 2 * sizeof (double), num_type); - - return type_id; -} - -// Callback data structure for passing data to hdf5_read_next_data, below. - -struct -hdf5_callback_data -{ - hdf5_callback_data (void) - : name (), global (false), tc (), doc (), - complex_type (hdf5_make_complex_type (H5T_NATIVE_DOUBLE)), - range_type (hdf5_make_range_type (H5T_NATIVE_DOUBLE)), - import (false) { } - - // the following fields are set by hdf5_read_data on successful return: - - // the name of the variable - std::string name; - - // whether it is global - bool global; - - // the value of the variable, in Octave form - octave_value tc; - - // a documentation string (NULL if none) - std::string doc; - - // the following fields are input to hdf5_read_data: - - // HDF5 rep's of complex and range type - hid_t complex_type, range_type; - - // whether to try extra hard to import "foreign" data - bool import; -}; - // This variable, set in read_hdf5_data(), tells whether we are using // a version of HDF5 with a buggy H5Giterate (i.e. which neglects to // increment the index parameter to the next unread item). @@ -366,10 +194,12 @@ // -1 on error, and 0 to tell H5Giterate to continue on to the next item // (e.g. if NAME was a data type we don't recognize). -static herr_t +herr_t hdf5_read_next_data (hid_t group_id, const char *name, void *dv) { hdf5_callback_data *d = static_cast <hdf5_callback_data *> (dv); + hid_t type_id = -1, type_class_id = -1, data_id = -1, subgroup_id = -1, + space_id = -1; H5G_stat_t info; herr_t retval = 0; @@ -380,7 +210,7 @@ // Allow identifiers as all digits so we can load lists saved by // earlier versions of Octave. - if (! ident_valid && (d->import || ident_is_all_digits (vname))) + if (! ident_valid ) { // fix the identifier, replacing invalid chars with underscores vname = make_valid_identifier (vname); @@ -391,297 +221,9 @@ H5Gget_objinfo (group_id, name, 1, &info); - if (info.type == H5G_DATASET && ident_valid) + if (info.type == H5G_GROUP && ident_valid) { - retval = 1; - - hid_t data_id = H5Dopen (group_id, name); - - if (data_id < 0) - { - retval = data_id; - - goto done; - } - - hid_t type_id = H5Dget_type (data_id); - - hid_t type_class_id = H5Tget_class (type_id); - -#if HAVE_HDF5_INT2FLOAT_CONVERSIONS - if (type_class_id == H5T_INTEGER || type_class_id == H5T_FLOAT) - { -#else - // hdf5 doesn't (yet) support automatic float/integer conversions - if (type_class_id == H5T_FLOAT) - { -#endif - // read real matrix or scalar variable - - hid_t space_id = H5Dget_space (data_id); - - hsize_t rank = H5Sget_simple_extent_ndims (space_id); - - if (rank == 0) - { - // real scalar: - double dtmp; - if (H5Dread (data_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, - H5P_DEFAULT, (void *) &dtmp) < 0) - retval = -1; // error - else - d->tc = dtmp; - } - else if (rank > 0 && rank <= 2) - { - // real matrix - OCTAVE_LOCAL_BUFFER (hsize_t, dims, rank); - OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank); - - H5Sget_simple_extent_dims (space_id, dims, maxdims); - - int nr, nc; // rows and columns - // octave uses column-major & HDF5 uses row-major - nc = dims[0]; - nr = rank > 1 ? dims[1] : 1; - Matrix m (nr, nc); - double *re = m.fortran_vec (); - if (H5Dread (data_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, - H5P_DEFAULT, (void *) re) < 0) - retval = -1; // error - else - d->tc = m; - } - else if (rank >= 3 && d->import) - { - OCTAVE_LOCAL_BUFFER (hsize_t, dims, rank); - OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank); - - H5Sget_simple_extent_dims (space_id, dims, maxdims); - - OCTAVE_LOCAL_BUFFER (hssize_t, start, rank); - OCTAVE_LOCAL_BUFFER (hsize_t, count, rank); - - for (hsize_t i = 0; i < rank; ++i) - { - start[i] = 0; - count[i] = 1; - } - count[0] = dims[0]; - count[1] = dims[1]; - retval = hdf5_import_multidim (data_id, space_id, - rank, dims, rank-1, - start, count, - H5T_NATIVE_DOUBLE, d->tc); - } - else - { - warning ("load: can't read %d-dim. hdf5 dataset %s", - rank, name); - retval = 0; // skip; we can't read 3+ dimensional datasets - } - - H5Sclose (space_id); - } - else if (type_class_id == H5T_STRING) - { - // read string variable - hid_t space_id = H5Dget_space (data_id); - hsize_t rank = H5Sget_simple_extent_ndims (space_id); - - if (rank == 0) - { - // a single string: - int slen = H5Tget_size (type_id); - if (slen < 0) - retval = -1; // error - else - { - OCTAVE_LOCAL_BUFFER (char, s, slen); - // create datatype for (null-terminated) string - // to read into: - hid_t st_id = H5Tcopy (H5T_C_S1); - H5Tset_size (st_id, slen); - if (H5Dread (data_id, st_id, H5S_ALL, H5S_ALL, - H5P_DEFAULT, (void *) s) < 0) - { - retval = -1; // error - } - else - d->tc = s; - - H5Tclose (st_id); - } - } - else if (rank == 1) - { - // string vector - hsize_t elements, maxdim; - H5Sget_simple_extent_dims (space_id, &elements, &maxdim); - int slen = H5Tget_size (type_id); - if (slen < 0) - retval = -1; // error - else - { - // hdf5 string arrays store strings of all the - // same physical length (I think), which is - // slightly wasteful, but oh well. - - OCTAVE_LOCAL_BUFFER (char, s, elements * slen); - - // create datatype for (null-terminated) string - // to read into: - hid_t st_id = H5Tcopy (H5T_C_S1); - H5Tset_size (st_id, slen); - - if (H5Dread (data_id, st_id, H5S_ALL, H5S_ALL, - H5P_DEFAULT, (void *) s) < 0) - retval = -1; // error - else - { - charMatrix chm (elements, slen - 1); - for (hsize_t i = 0; i < elements; ++i) - { - chm.insert (s + i*slen, i, 0); - } - d->tc = octave_value (chm, true); - } - - H5Tclose (st_id); - } - } - else - { - warning ("load: can't read %d-dim. hdf5 string vector %s", - rank, name); - // skip; we can't read higher-dimensional string vectors - retval = 0; - } - } - else if (type_class_id == H5T_COMPOUND) - { - // check for complex or range data: - - if (hdf5_types_compatible (type_id, d->complex_type)) - { - // read complex matrix or scalar variable - - hid_t space_id = H5Dget_space (data_id); - hsize_t rank = H5Sget_simple_extent_ndims (space_id); - - if (rank == 0) - { - // complex scalar: - Complex ctmp; - if (H5Dread (data_id, d->complex_type, H5S_ALL, - H5S_ALL, H5P_DEFAULT, - (void *) X_CAST (double *, &ctmp)) < 0) - retval = -1; // error - else - d->tc = ctmp; - } - else if (rank > 0 && rank <= 2) - { - // complex matrix - OCTAVE_LOCAL_BUFFER (hsize_t, dims, rank); - OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank); - H5Sget_simple_extent_dims (space_id, dims, maxdims); - int nr, nc; // rows and columns - // octave uses column-major & HDF5 uses row-major - nc = dims[0]; - nr = rank > 1 ? dims[1] : 1; - ComplexMatrix m (nr, nc); - Complex *reim = m.fortran_vec (); - if (H5Dread (data_id, d->complex_type, H5S_ALL, - H5S_ALL, H5P_DEFAULT, - (void *) X_CAST (double *, reim)) < 0) - retval = -1; // error - else - d->tc = m; - } - else if (rank >= 3 && d->import) - { - OCTAVE_LOCAL_BUFFER (hsize_t, dims, rank); - OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank); - H5Sget_simple_extent_dims (space_id, dims, maxdims); - OCTAVE_LOCAL_BUFFER (hssize_t, start, rank); - OCTAVE_LOCAL_BUFFER (hsize_t, count, rank); - for (hsize_t i = 0; i < rank; ++i) - { - start[i] = 0; - count[i] = 1; - } - count[0] = dims[0]; - count[1] = dims[1]; - retval = hdf5_import_multidim (data_id, space_id, - rank, dims, rank-1, - start, count, - d->complex_type, - d->tc); - } - else - { - warning ("load: can't read %d-dim. hdf5 dataset %s", - rank, name); - // skip; we can't read 3+ dimensional datasets - retval = 0; - } - H5Sclose (space_id); - } - else if (hdf5_types_compatible (type_id, d->range_type)) - { - // read range variable: - hid_t space_id = H5Dget_space (data_id); - hsize_t rank = H5Sget_simple_extent_ndims (space_id); - - if (rank == 0) - { - double rangevals[3]; - if (H5Dread (data_id, d->range_type, H5S_ALL, H5S_ALL, - H5P_DEFAULT, (void *) rangevals) < 0) - retval = -1; // error - else - { - Range r (rangevals[0], rangevals[1], rangevals[2]); - d->tc = r; - } - } - else - { - warning ("load: can't read range array `%s' in hdf5 file", - name); - // skip; we can't read arrays of range variables - retval = 0; - } - - H5Sclose (space_id); - } - else - { - warning ("load: can't read `%s' (unknown compound datatype)", - name); - retval = 0; // unknown datatype; skip. - } - } - else - { - warning ("load: can't read `%s' (unknown datatype)", name); - retval = 0; // unknown datatype; skip - } - - H5Tclose (type_id); - - // check for OCTAVE_GLOBAL attribute: - d->global = hdf5_check_attr (data_id, "OCTAVE_GLOBAL"); - - H5Dclose (data_id); - } - else if (info.type == H5G_GROUP && ident_valid) - { - // read in group as a list or a structure - retval = 1; - - hid_t subgroup_id = H5Gopen (group_id, name); + subgroup_id = H5Gopen (group_id, name); if (subgroup_id < 0) { @@ -689,56 +231,153 @@ goto done; } - // an HDF5 group is treated as an octave structure by - // default (since that preserves name information), and an - // octave list otherwise. - - bool is_list = hdf5_check_attr (subgroup_id, "OCTAVE_LIST"); - - hdf5_callback_data dsub; - - dsub.complex_type = d->complex_type; - dsub.range_type = d->range_type; - dsub.import = d->import; + if (hdf5_check_attr (subgroup_id, "OCTAVE_NEW_FORMAT")) + { + data_id = H5Dopen (subgroup_id, "type"); - herr_t retval2; - octave_value_list lst; - Octave_map m; - int current_item = 0; - while ((retval2 = H5Giterate (group_id, name, ¤t_item, - hdf5_read_next_data, &dsub)) > 0) - { - if (is_list) - lst.append (dsub.tc); - else + if (data_id < 0) { - octave_value ov = dsub.tc; - - if (ov.is_list ()) - m.assign (dsub.name, octave_value (ov.list_value ())); - else - m.assign (dsub.name, ov); + retval = data_id; + goto done; } - if (have_h5giterate_bug) - current_item++; // H5Giterate returned the last index processed + type_id = H5Dget_type (data_id); + + type_class_id = H5Tget_class (type_id); + + if (type_class_id != H5T_STRING) + goto done; + + space_id = H5Dget_space (data_id); + hsize_t rank = H5Sget_simple_extent_ndims (space_id); + + if (rank != 0) + goto done; + + int slen = H5Tget_size (type_id); + if (slen < 0) + goto done; + + OCTAVE_LOCAL_BUFFER (char, typ, slen); + + // create datatype for (null-terminated) string to read into: + hid_t st_id = H5Tcopy (H5T_C_S1); + H5Tset_size (st_id, slen); + + if (H5Dread (data_id, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, + (void *) typ) < 0) + goto done; + + H5Tclose (st_id); + H5Dclose (data_id); + + d->tc = octave_value_typeinfo::lookup_type (typ); + + retval = (d->tc.load_hdf5 (subgroup_id, "value", + have_h5giterate_bug) ? 1 : -1); + + // check for OCTAVE_GLOBAL attribute: + d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL"); + + H5Gclose (subgroup_id); } - - if (retval2 < 0) - retval = retval2; else { - d->global = hdf5_check_attr (group_id, "OCTAVE_GLOBAL"); + // an HDF5 group is treated as an octave structure by + // default (since that preserves name information), and an + // octave list otherwise. + + if (hdf5_check_attr (subgroup_id, "OCTAVE_LIST")) + d->tc = octave_value_typeinfo::lookup_type ("list"); + else + d->tc = octave_value_typeinfo::lookup_type ("cell"); + + // check for OCTAVE_GLOBAL attribute: + d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL"); + + H5Gclose (subgroup_id); - if (is_list) - d->tc = octave_value (lst); - else - d->tc = m; + retval = (d->tc.load_hdf5 (group_id, name, have_h5giterate_bug) + ? 1 : -1); + } + + } + else if (info.type == H5G_DATASET && ident_valid) + { + // For backwards compatiability. + data_id = H5Dopen (group_id, name); + + if (data_id < 0) + { + retval = data_id; + goto done; } - H5Gclose (subgroup_id); + type_id = H5Dget_type (data_id); + + type_class_id = H5Tget_class (type_id); + +#if HAVE_HDF5_INT2FLOAT_CONVERSIONS + if (type_class_id == H5T_INTEGER || type_class_id == H5T_FLOAT) +#else + // hdf5 doesn't (yet) support automatic float/integer conversions + if (type_class_id == H5T_FLOAT) +#endif + { + space_id = H5Dget_space (data_id); + + hsize_t rank = H5Sget_simple_extent_ndims (space_id); + + if (rank == 0) + d->tc = octave_value_typeinfo::lookup_type ("scalar"); + else + d->tc = octave_value_typeinfo::lookup_type ("matrix"); + + H5Sclose (space_id); + } + else if (type_class_id == H5T_STRING) + d->tc = octave_value_typeinfo::lookup_type ("string"); + else if (type_class_id == H5T_COMPOUND) + { + hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE); + + if (hdf5_types_compatible (type_id, complex_type)) + { + // read complex matrix or scalar variable + space_id = H5Dget_space (data_id); + hsize_t rank = H5Sget_simple_extent_ndims (space_id); + + if (rank == 0) + d->tc = octave_value_typeinfo::lookup_type ("complex scalar"); + else + d->tc = octave_value_typeinfo::lookup_type ("complex matrix"); + + H5Sclose (space_id); + } + else + // Assume that if its not complex its a range. If its not + // it'll be rejected later in the range code + d->tc = octave_value_typeinfo::lookup_type ("range"); + + H5Tclose (complex_type); + } + else + { + warning ("load: can't read `%s' (unknown datatype)", name); + retval = 0; // unknown datatype; skip + } + + // check for OCTAVE_GLOBAL attribute: + d->global = hdf5_check_attr (data_id, "OCTAVE_GLOBAL"); + + H5Tclose (type_id); + H5Dclose (data_id); + + retval = (d->tc.load_hdf5 (group_id, name, have_h5giterate_bug) + ? 1 : -1); } - else if (! ident_valid) + + if (!ident_valid) { // should we attempt to handle invalid identifiers by converting // bad characters to '_', say? @@ -747,10 +386,9 @@ } done: - if (retval < 0) error ("load: error while reading hdf5 item %s", name); - + if (retval > 0) { // get documentation string, if any: @@ -764,7 +402,7 @@ } else if (vname != name) { - // the name was changed by import; store the original name + // the name was changed; store the original name // as the documentation string: d->doc = name; } @@ -780,13 +418,10 @@ // an hdf5_ifstream. Return the variable value in tc, its doc string // in doc, and whether it is global in global. The return value is // the name of the variable, or NULL if none were found or there was -// and error. If import is true, we try extra hard to import "foreign" -// datasets (not created by Octave), although we usually do a reasonable -// job anyway. (c.f. load -import documentation.) +// and error. std::string -read_hdf5_data (std::istream& is, - const std::string& /* filename */, bool& global, - octave_value& tc, std::string& doc, bool import) +read_hdf5_data (std::istream& is, const std::string& /* filename */, + bool& global, octave_value& tc, std::string& doc) { std::string retval; @@ -795,8 +430,6 @@ hdf5_ifstream& hs = (hdf5_ifstream&) is; hdf5_callback_data d; - d.import = import; - // Versions of HDF5 prior to 1.2.2 had a bug in H5Giterate where it // would return the index of the last item processed instead of the // next item to be processed, forcing us to increment the index manually. @@ -835,9 +468,6 @@ // hdf5_read_next_data already printed one, probably. } - H5Tclose (d.complex_type); - H5Tclose (d.range_type); - if (! d.name.empty ()) retval = d.name; @@ -877,7 +507,6 @@ return retval; } - // save_type_to_hdf5 is not currently used, since hdf5 doesn't yet support // automatic float<->integer conversions: @@ -885,7 +514,7 @@ // return the HDF5 type id corresponding to the Octave save_type -static hid_t +hid_t save_type_to_hdf5 (save_type st) { switch (st) @@ -923,297 +552,68 @@ // successful. This function calls itself recursively for lists // (stored as HDF5 groups). -static bool +bool add_hdf5_data (hid_t loc_id, const octave_value& tc, const std::string& name, const std::string& doc, bool mark_as_global, bool save_as_floats) { hsize_t dims[3]; - hid_t type_id = -1, space_id = -1, data_id = -1; - bool data_is_group = 0; - bool retval = 0; - - if (tc.is_string ()) - { - int nr = tc.rows (); - charMatrix chm = tc.char_matrix_value (); - int nc = chm.cols (); - - // create datatype for (null-terminated) string to write from: - type_id = H5Tcopy (H5T_C_S1); H5Tset_size (type_id, nc + 1); - if (type_id < 0) - goto error_cleanup; - - dims[0] = nr; - space_id = H5Screate_simple (nr > 0 ? 1 : 0, dims, (hsize_t*) 0); - if (space_id < 0) - goto error_cleanup; - - data_id = H5Dcreate (loc_id, name.c_str (), - type_id, space_id, H5P_DEFAULT); - if (data_id < 0) - goto error_cleanup; - - OCTAVE_LOCAL_BUFFER (char, s, nr * (nc + 1)); - - for (int i = 0; i < nr; ++i) - { - std::string tstr = chm.row_as_string (i); - strcpy (s + i * (nc+1), tstr.c_str ()); - } - - if (H5Dwrite (data_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, - (void*) s) < 0) { - goto error_cleanup; - } - } - else if (tc.is_range ()) - { - space_id = H5Screate_simple (0, dims, (hsize_t*) 0); - if (space_id < 0) - goto error_cleanup; - - type_id = hdf5_make_range_type (H5T_NATIVE_DOUBLE); - if (type_id < 0) - goto error_cleanup; - - data_id = H5Dcreate (loc_id, name.c_str (), - type_id, space_id, H5P_DEFAULT); - if (data_id < 0) - goto error_cleanup; - - Range r = tc.range_value (); - double range_vals[3]; - range_vals[0] = r.base (); - range_vals[1] = r.limit (); - range_vals[2] = r.inc (); + hid_t type_id = -1, space_id = -1, data_id = -1, data_type_id = -1; + bool retval = false; + octave_value val = tc; + std::string t = tc.type_name(); - if (H5Dwrite (data_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, - (void*) range_vals) < 0) - goto error_cleanup; - } - else if (tc.is_real_scalar ()) - { - space_id = H5Screate_simple (0, dims, (hsize_t*) 0); - if (space_id < 0) goto error_cleanup; - - data_id = H5Dcreate (loc_id, name.c_str (), - H5T_NATIVE_DOUBLE, space_id, H5P_DEFAULT); - if (data_id < 0) - goto error_cleanup; - - double tmp = tc.double_value (); - if (H5Dwrite (data_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, - H5P_DEFAULT, (void*) &tmp) < 0) - goto error_cleanup; - } - else if (tc.is_real_matrix ()) - { - Matrix m = tc.matrix_value (); - dims[1] = m.rows (); // Octave uses column-major, while - dims[0] = m.columns (); // HDF5 uses row-major ordering - - space_id = H5Screate_simple (dims[1] > 1 ?2:1, dims, (hsize_t*) 0); - if (space_id < 0) - goto error_cleanup; - - hid_t save_type_id = H5T_NATIVE_DOUBLE; - - if (save_as_floats) - { - if (m.too_large_for_float ()) - { - warning ("save: some values too large to save as floats --"); - warning ("save: saving as doubles instead"); - } - else - save_type_id = H5T_NATIVE_FLOAT; - } -#if HAVE_HDF5_INT2FLOAT_CONVERSIONS - // hdf5 currently doesn't support float/integer conversions - else - { - double max_val, min_val; - - if (m.all_integers (max_val, min_val)) - save_type_id - = save_type_to_hdf5 (get_save_type (max_val, min_val)); - } -#endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */ - - data_id = H5Dcreate (loc_id, name.c_str (), - save_type_id, space_id, H5P_DEFAULT); - if (data_id < 0) - goto error_cleanup; - - double *mtmp = m.fortran_vec (); - if (H5Dwrite (data_id, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, - H5P_DEFAULT, (void*) mtmp) < 0) - goto error_cleanup; - } - else if (tc.is_complex_scalar ()) - { - space_id = H5Screate_simple (0, dims, (hsize_t*) 0); - if (space_id < 0) - goto error_cleanup; + data_id = H5Gcreate (loc_id, name.c_str (), 0); + if (data_id < 0) + goto error_cleanup; - type_id = hdf5_make_complex_type (H5T_NATIVE_DOUBLE); - if (type_id < 0) - goto error_cleanup; - - data_id = H5Dcreate (loc_id, name.c_str (), - type_id, space_id, H5P_DEFAULT); - if (data_id < 0) - goto error_cleanup; - - Complex tmp = tc.complex_value (); - if (H5Dwrite (data_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, - (void*) X_CAST (double*, &tmp)) < 0) - goto error_cleanup; - } - else if (tc.is_complex_matrix ()) - { - ComplexMatrix m = tc.complex_matrix_value (); - - dims[1] = m.rows (); // Octave uses column-major, while - dims[0] = m.columns (); // HDF5 uses row-major ordering - - space_id = H5Screate_simple (dims[1] > 1 ?2:1, dims, (hsize_t*) 0); - if (space_id < 0) - goto error_cleanup; - - hid_t save_type_id = H5T_NATIVE_DOUBLE; - - if (save_as_floats) - { - if (m.too_large_for_float ()) - { - warning ("save: some values too large to save as floats --"); - warning ("save: saving as doubles instead"); - } - else - save_type_id = H5T_NATIVE_FLOAT; - } -#if HAVE_HDF5_INT2FLOAT_CONVERSIONS - // hdf5 currently doesn't support float/integer conversions - else - { - double max_val, min_val; - - if (m.all_integers (max_val, min_val)) - save_type_id - = save_type_to_hdf5 (get_save_type (max_val, min_val)); - } -#endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */ - - type_id = hdf5_make_complex_type (save_type_id); - if (type_id < 0) goto error_cleanup; - - data_id = H5Dcreate (loc_id, name.c_str (), - type_id, space_id, H5P_DEFAULT); - if (data_id < 0) - goto error_cleanup; - - hid_t complex_type_id = hdf5_make_complex_type (H5T_NATIVE_DOUBLE); - if (complex_type_id < 0) - goto error_cleanup; + // attach the type of the variable + type_id = H5Tcopy (H5T_C_S1); H5Tset_size (type_id, t.length () + 1); + if (type_id < 0) + goto error_cleanup; - Complex *mtmp = m.fortran_vec (); - if (H5Dwrite (data_id, complex_type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, - (void*) X_CAST (double *, mtmp)) < 0) - { - H5Tclose (complex_type_id); - goto error_cleanup; - } - - H5Tclose (complex_type_id); - } - else if (tc.is_list ()) - { - data_id = H5Gcreate (loc_id, name.c_str (), 0); - if (data_id < 0) - goto error_cleanup; - - data_is_group = 1; - - // recursively add each element of the list to this group - octave_value_list lst = tc.list_value (); - - for (int i = 0; i < lst.length (); ++i) - { - // should we use lst.name_tags () to label the elements? - char s[20]; - sprintf (s, "_%d", i); - bool retval2 = add_hdf5_data (data_id, lst (i), s, "", - false, save_as_floats); - if (! retval2) - goto error_cleanup; - } + dims[0] = 0; + space_id = H5Screate_simple (0 , dims, (hsize_t*) 0); + if (space_id < 0) + goto error_cleanup; - // mark with an attribute "OCTAVE_LIST" with value 1 - // to distinguish from structures (also stored as HDF5 groups): - if (hdf5_add_attr (data_id, "OCTAVE_LIST") < 0) - goto error_cleanup; - } - else if (tc.is_map ()) - { - // an Octave structure - data_id = H5Gcreate (loc_id, name.c_str (), 0); - if (data_id < 0) - goto error_cleanup; - - data_is_group = 1; + data_type_id = H5Dcreate (data_id, "type", type_id, space_id, H5P_DEFAULT); + if (data_type_id < 0 || H5Dwrite (data_type_id, type_id, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void*) t.c_str ()) < 0) + goto error_cleanup; - // recursively add each element of the structure to this group - const Octave_map m = tc.map_value (); - Octave_map::const_iterator i = m.begin (); - while (i != m.end ()) - { - // XXX FIXME XXX -- if the length of the structure array is - // 1, should we really create a list object? - bool retval2 = add_hdf5_data (data_id, octave_value (m.contents (i)), - m.key (i), "", false, save_as_floats); - if (! retval2) - goto error_cleanup; - - i++; - } - } - else - { - gripe_wrong_type_arg ("save", tc, false); - goto error_cleanup; - } + // Now call the real function to save the variable + retval = val.save_hdf5 (data_id, "value", save_as_floats); // attach doc string as comment: - if (doc.length () > 0 + if (retval && doc.length () > 0 && H5Gset_comment (loc_id, name.c_str (), doc.c_str ()) < 0) - goto error_cleanup; - - retval = 1; + retval = false; // if it's global, add an attribute "OCTAVE_GLOBAL" with value 1 - if (mark_as_global) + if (retval && mark_as_global) retval = hdf5_add_attr (data_id, "OCTAVE_GLOBAL") >= 0; + // We are saving in the new variable format, so mark it + if (retval) + retval = hdf5_add_attr (data_id, "OCTAVE_NEW_FORMAT") >= 0; + error_cleanup: - if (! retval) - error ("save: error while writing `%s' to hdf5 file", name.c_str ()); + if (data_type_id >= 0) + H5Dclose (data_type_id); - if (data_id >= 0) - { - if (data_is_group) - H5Gclose (data_id); - else - H5Dclose (data_id); - } + if (type_id >= 0) + H5Tclose (type_id); if (space_id >= 0) H5Sclose (space_id); - if (type_id >= 0) - H5Tclose (type_id); + if (data_id >= 0) + H5Gclose (data_id); + + if (! retval) + error ("save: error while writing `%s' to hdf5 file", name.c_str ()); return retval; }
--- a/src/ls-hdf5.h +++ b/src/ls-hdf5.h @@ -109,10 +109,51 @@ { hdf5_fstreambase::open (name, mode, prot); } }; +// Callback data structure for passing data to hdf5_read_next_data, below. + +struct +hdf5_callback_data +{ + hdf5_callback_data (void) + : name (), global (false), tc (), doc () { } + + // the following fields are set by hdf5_read_data on successful return: + + // the name of the variable + std::string name; + + // whether it is global + bool global; + + // the value of the variable, in Octave form + octave_value tc; + + // a documentation string (NULL if none) + std::string doc; +}; + +#if HAVE_HDF5_INT2FLOAT_CONVERSIONS +extern hid_t +save_type_to_hdf5 (save_type st) +#endif + +extern hid_t +hdf5_make_complex_type (hid_t num_type); + +extern bool +hdf5_types_compatible (hid_t t1, hid_t t2); + +extern herr_t +hdf5_read_next_data (hid_t group_id, const char *name, void *dv); + +extern bool +add_hdf5_data (hid_t loc_id, const octave_value& tc, + const std::string& name, const std::string& doc, + bool mark_as_global, bool save_as_floats); + extern std::string -read_hdf5_data (std::istream& is, - const std::string& filename, bool& global, - octave_value& tc, std::string& doc, bool import); +read_hdf5_data (std::istream& is, const std::string& filename, bool& global, + octave_value& tc, std::string& doc); extern bool save_hdf5_data (std::ostream& os, const octave_value& tc,
--- a/src/ls-oct-ascii.cc +++ b/src/ls-oct-ascii.cc @@ -26,7 +26,6 @@ #include <config.h> #endif -#include <cfloat> #include <cstring> #include <cctype> @@ -71,27 +70,8 @@ // The number of decimal digits to use when writing ascii data. static int Vsave_precision; -#define CELL_ELT_TAG "<cell-element>" - -// Used when converting Inf to something that gnuplot can read. - -#ifndef OCT_RBV -#define OCT_RBV DBL_MAX / 100.0 -#endif - // Functions for reading ascii data. -static void -ascii_save_type (std::ostream& os, const char *type, bool mark_as_global) -{ - if (mark_as_global) - os << "# type: global "; - else - os << "# type: "; - - os << type << "\n"; -} - static Matrix strip_infnan (const Matrix& m) { @@ -123,69 +103,6 @@ return retval; } -static ComplexMatrix -strip_infnan (const ComplexMatrix& m) -{ - int nr = m.rows (); - int nc = m.columns (); - - ComplexMatrix retval (nr, nc); - - int k = 0; - for (int i = 0; i < nr; i++) - { - for (int j = 0; j < nc; j++) - { - Complex c = m (i, j); - if (xisnan (c)) - goto next_row; - else - { - double re = real (c); - double im = imag (c); - - re = xisinf (re) ? (re > 0 ? OCT_RBV : -OCT_RBV) : re; - im = xisinf (im) ? (im > 0 ? OCT_RBV : -OCT_RBV) : im; - - retval (k, j) = Complex (re, im); - } - } - k++; - - next_row: - continue; - } - - if (k > 0) - retval.resize (k, nc); - - return retval; -} - -// Skip white space and comments on stream IS. - -static void -skip_comments (std::istream& is) -{ - char c = '\0'; - while (is.get (c)) - { - if (c == ' ' || c == '\t' || c == '\n') - ; // Skip whitespace on way to beginning of next line. - else - break; - } - - for (;;) - { - if (is && (c == '%' || c == '#')) - while (is.get (c) && c != '\n') - ; // Skip to beginning of next line, ignoring everything. - else - break; - } -} - // Extract a KEYWORD and its value from stream IS, returning the // associated value in a new string. // @@ -194,7 +111,7 @@ // [%#][ \t]*keyword[ \t]*:[ \t]*string-value[ \t]*\n std::string -extract_keyword (std::istream& is, const char *keyword) +extract_keyword (std::istream& is, const char *keyword, const bool next_only) { std::string retval; @@ -236,6 +153,8 @@ OSSTREAM_FREEZE (value); break; } + else if (next_only) + break; } } @@ -267,8 +186,9 @@ // // [%#][ \t]*keyword[ \t]*int-value.*\n -static bool -extract_keyword (std::istream& is, const char *keyword, int& value) +bool +extract_keyword (std::istream& is, const char *keyword, int& value, + const bool next_only) { bool status = false; value = 0; @@ -308,6 +228,8 @@ ; // Skip to beginning of next line; break; } + else if (next_only) + break; } } return status; @@ -317,6 +239,9 @@ // place it in TC, returning the name of the variable. If the value // is tagged as global in the file, return TRUE in GLOBAL. // +// Each type supplies its own function to load the data, and so this +// function is extensible. +// // FILENAME is used for error messages. // // The data is expected to be in the following format: @@ -334,7 +259,7 @@ // # type: <type> // # <info> // -// Where: +// Where, for the built in types are: // // <name> : a valid identifier // @@ -345,21 +270,25 @@ // | complex scalar // | matrix // | complex matrix +// | bool +// | bool matrix // | string // | range -// | string array // // <info> : <matrix info> // | <string info> -// | <string array info> // // <matrix info> : # rows: <integer> // : # columns: <integer> // -// <string info> : # length: <integer> +// <string info> : # elements: <integer> +// : # length: <integer> (once before each string) // -// <string array info> : # elements: <integer> -// : # length: <integer> (once before each string) +// For backward compatibility the type "string array" is treated as a +// "string" type. Also "string" can have a single element with no elements +// line such that +// +// <string info> : # length: <integer> // // Formatted ASCII data follows the header. // @@ -375,7 +304,7 @@ // Example: // // # name: foo -// # type: string array +// # type: string // # elements: 5 // # length: 4 // this @@ -389,7 +318,8 @@ // array // // XXX FIXME XXX -- this format is fairly rigid, and doesn't allow for -// arbitrary comments, etc. Someone should fix that. +// arbitrary comments. Someone should fix that. It does allow arbitrary +// types however. // Ugh. The signature of the compare method is not standard in older // versions of the GNU libstdc++. Do this instead: @@ -442,196 +372,13 @@ else typ = tag; - if (SUBSTRING_COMPARE_EQ (typ, 0, 6, "scalar")) - { - double tmp = octave_read_double (is); - if (is) - tc = tmp; - else - error ("load: failed to load scalar constant"); - } - else if (SUBSTRING_COMPARE_EQ (typ, 0, 6, "matrix")) - { - int nr = 0; - int nc = 0; - - if (extract_keyword (is, "rows", nr) && nr >= 0 - && extract_keyword (is, "columns", nc) && nc >= 0) - { - if (nr > 0 && nc > 0) - { - Matrix tmp (nr, nc); - is >> tmp; - if (is) - tc = tmp; - else - error ("load: failed to load matrix constant"); - } - else if (nr == 0 || nc == 0) - tc = Matrix (nr, nc); - else - panic_impossible (); - } - else - error ("load: failed to extract number of rows and columns"); - } - else if (SUBSTRING_COMPARE_EQ (typ, 0, 4, "cell")) - { - int nr = 0; - int nc = 0; - - if (extract_keyword (is, "rows", nr) && nr >= 0 - && extract_keyword (is, "columns", nc) && nc >= 0) - { - if (nr > 0 && nc > 0) - { - Cell tmp (nr, nc); - - for (int j = 0; j < nc; j++) - { - for (int i = 0; i < nr; i++) - { - octave_value t2; - - // recurse to read cell elements - std::string nm - = read_ascii_data (is, filename, global, t2, count); - - if (nm == CELL_ELT_TAG) - { - if (is) - tmp.elem (i, j) = t2; - } - else - { - error ("load: cell array element had unexpected name"); - goto cell_read_error; - } - } - } - - cell_read_error: + // Special case for backward compatiablity. A small bit of cruft + if (SUBSTRING_COMPARE_EQ (typ, 0, 12, "string array")) + tc = octave_value (charMatrix (), true); + else + tc = octave_value_typeinfo::lookup_type (typ); - if (is) - tc = tmp; - else - error ("load: failed to load cell element"); - } - else if (nr == 0 || nc == 0) - tc = Cell (nr, nc); - else - panic_impossible (); - } - else - error ("load: failed to extract number of rows and columns for cell array"); - } - else if (SUBSTRING_COMPARE_EQ (typ, 0, 14, "complex scalar")) - { - Complex tmp = octave_read_complex (is); - if (is) - tc = tmp; - else - error ("load: failed to load complex scalar constant"); - } - else if (SUBSTRING_COMPARE_EQ (typ, 0, 14, "complex matrix")) - { - int nr = 0; - int nc = 0; - - if (extract_keyword (is, "rows", nr) && nr > 0 - && extract_keyword (is, "columns", nc) && nc > 0) - { - ComplexMatrix tmp (nr, nc); - is >> tmp; - if (is) - tc = tmp; - else - error ("load: failed to load complex matrix constant"); - } - else - error ("load: failed to extract number of rows and columns"); - } - else if (SUBSTRING_COMPARE_EQ (typ, 0, 12, "string array")) - { - int elements; - if (extract_keyword (is, "elements", elements) && elements >= 0) - { - // XXX FIXME XXX -- need to be able to get max length - // before doing anything. - - charMatrix chm (elements, 0); - int max_len = 0; - for (int i = 0; i < elements; i++) - { - int len; - if (extract_keyword (is, "length", len) && len >= 0) - { - OCTAVE_LOCAL_BUFFER (char, tmp, len+1); - - if (len > 0 && ! is.read (X_CAST (char *, tmp), len)) - { - error ("load: failed to load string constant"); - break; - } - else - { - tmp [len] = '\0'; - if (len > max_len) - { - max_len = len; - chm.resize (elements, max_len, 0); - } - chm.insert (tmp, i, 0); - } - } - else - error ("load: failed to extract string length for element %d", i+1); - } - - if (! error_state) - tc = octave_value (chm, true); - } - else - error ("load: failed to extract number of string elements"); - } - else if (SUBSTRING_COMPARE_EQ (typ, 0, 6, "string")) - { - int len; - if (extract_keyword (is, "length", len) && len >= 0) - { - OCTAVE_LOCAL_BUFFER (char, tmp, len+1); - - if (len > 0 && ! is.read (X_CAST (char *, tmp), len)) - { - error ("load: failed to load string constant"); - } - else - { - tmp [len] = '\0'; - - if (is) - tc = tmp; - else - error ("load: failed to load string constant"); - } - } - else - error ("load: failed to extract string length"); - } - else if (SUBSTRING_COMPARE_EQ (typ, 0, 5, "range")) - { - // # base, limit, range comment added by save (). - - skip_comments (is); - Range tmp; - is >> tmp; - if (is) - tc = tmp; - else - error ("load: failed to load range constant"); - } - else - error ("load: unknown constant type `%s'", tag.c_str ()); + tc.load_ascii (is); } else error ("load: failed to extract keyword specifying value type"); @@ -679,186 +426,12 @@ octave_value val = val_arg; - if (val.is_range ()) - { - Range r = val.range_value (); - double base = r.base (); - double limit = r.limit (); - double inc = r.inc (); - if (! (NINT (base) == base - && NINT (limit) == limit - && NINT (inc) == inc)) - val = val.matrix_value (); - } - - if (val.is_string ()) - { - ascii_save_type (os, "string array", mark_as_global); - charMatrix chm = val.char_matrix_value (); - int elements = chm.rows (); - os << "# elements: " << elements << "\n"; - for (int i = 0; i < elements; i++) - { - unsigned len = chm.cols (); - os << "# length: " << len << "\n"; - std::string tstr = chm.row_as_string (i, false, true); - const char *tmp = tstr.data (); - if (tstr.length () > len) - panic_impossible (); - os.write (X_CAST (char *, tmp), len); - os << "\n"; - } - } - else if (val.is_range ()) - { - ascii_save_type (os, "range", mark_as_global); - Range tmp = val.range_value (); - os << "# base, limit, increment\n"; - octave_write_double (os, tmp.base ()); - os << " "; - octave_write_double (os, tmp.limit ()); - os << " "; - octave_write_double (os, tmp.inc ()); - os << "\n"; - } - else if (val.is_real_scalar ()) - { - ascii_save_type (os, "scalar", mark_as_global); - - double d = val.double_value (); - - if (strip_nan_and_inf) - { - if (xisnan (d)) - { - error ("only value to plot is NaN"); - success = false; - } - else - { - d = xisinf (d) ? (d > 0 ? OCT_RBV : -OCT_RBV) : d; - octave_write_double (os, d); - os << "\n"; - } - } - else - { - if (! infnan_warned && (xisnan (d) || xisinf (d))) - { - warning ("save: Inf or NaN values may not be reloadable"); - infnan_warned = true; - } - - octave_write_double (os, d); - os << "\n"; - } - } - else if (val.is_real_matrix ()) - { - ascii_save_type (os, "matrix", mark_as_global); - - os << "# rows: " << val.rows () << "\n" - << "# columns: " << val.columns () << "\n"; - - Matrix tmp = val.matrix_value (); + if (mark_as_global) + os << "# type: global " << val.type_name () << "\n"; + else + os << "# type: " << val.type_name() << "\n"; - if (strip_nan_and_inf) - tmp = strip_infnan (tmp); - else if (! infnan_warned && tmp.any_element_is_inf_or_nan ()) - { - warning ("save: Inf or NaN values may not be reloadable"); - infnan_warned = true; - } - - os << tmp; - } - else if (val.is_cell ()) - { - ascii_save_type (os, "cell", mark_as_global); - - os << "# rows: " << val.rows () << "\n" - << "# columns: " << val.columns () << "\n"; - - Cell tmp = val.cell_value (); - - for (int j = 0; j < tmp.cols (); j++) - { - for (int i = 0; i < tmp.rows (); i++) - { - octave_value o_val = tmp.elem (i, j); - - // Recurse to print sub-value. - bool b = save_ascii_data (os, o_val, CELL_ELT_TAG, - infnan_warned, strip_nan_and_inf, - mark_as_global, 0); - - if (! b) - return os; - } - - os << "\n"; - } - } - else if (val.is_complex_scalar ()) - { - ascii_save_type (os, "complex scalar", mark_as_global); - - Complex c = val.complex_value (); - - if (strip_nan_and_inf) - { - if (xisnan (c)) - { - error ("only value to plot is NaN"); - success = false; - } - else - { - double re = real (c); - double im = imag (c); - - re = xisinf (re) ? (re > 0 ? OCT_RBV : -OCT_RBV) : re; - im = xisinf (im) ? (im > 0 ? OCT_RBV : -OCT_RBV) : im; - - c = Complex (re, im); - - octave_write_complex (os, c); - os << "\n"; - } - } - else - { - if (! infnan_warned && (xisnan (c) || xisinf (c))) - { - warning ("save: Inf or NaN values may not be reloadable"); - infnan_warned = true; - } - - octave_write_complex (os, c); - os << "\n"; - } - } - else if (val.is_complex_matrix ()) - { - ascii_save_type (os, "complex matrix", mark_as_global); - - os << "# rows: " << val.rows () << "\n" - << "# columns: " << val.columns () << "\n"; - - ComplexMatrix tmp = val.complex_matrix_value (); - - if (strip_nan_and_inf) - tmp = strip_infnan (tmp); - else if (! infnan_warned && tmp.any_element_is_inf_or_nan ()) - { - warning ("save: Inf or NaN values may not be reloadable"); - infnan_warned = true; - } - - os << tmp; - } - else - gripe_wrong_type_arg ("save", val, false); + success = val . save_ascii(os, infnan_warned, strip_nan_and_inf); os.precision (old_precision);
--- a/src/ls-oct-ascii.h +++ b/src/ls-oct-ascii.h @@ -23,8 +23,24 @@ #if !defined (octave_ls_oct_ascii_h) #define octave_ls_oct_ascii_h 1 +#include <cfloat> + +// Flag for cell elements +#define CELL_ELT_TAG "<cell-element>" + +// Used when converting Inf to something that gnuplot can read. + +#ifndef OCT_RBV +#define OCT_RBV DBL_MAX / 100.0 +#endif + extern std::string -extract_keyword (std::istream& is, const char *keyword); +extract_keyword (std::istream& is, const char *keyword, + const bool next_only = false); + +extern bool +extract_keyword (std::istream& is, const char *keyword, int& value, + const bool next_only = false); extern std::string read_ascii_data (std::istream& is, const std::string& filename, bool& global,
--- a/src/ls-oct-binary.cc +++ b/src/ls-oct-binary.cc @@ -99,43 +99,37 @@ // // global flag integer 1 // -// data type integer 1 +// data type char 1 // -// data (one of): -// -// scalar: -// data real 8 +// In general "data type" is 255, and in that case the next arguments +// in the data set are // -// complex scalar: -// data complex 16 +// object type bytes +// ------ ---- ----- +// type_length integer 4 // -// matrix: -// rows integer 4 -// columns integer 4 -// data real r*c*8 +// type string type_length +// +// The string "type" is then used with octave_value_typeinfo::lookup_type +// to create an octave_value of the correct type. The specific load/save +// function is then called. // -// complex matrix: -// rows integer 4 -// columns integer 4 -// data complex r*c*16 -// -// string: -// length int 4 -// data string length +// For backward compatiablity "data type" can also be a value between 1 +// and 7, where this defines a hardcoded octave_value of the type // -// range: -// base real 8 -// limit real 8 -// increment real 8 +// data type octave_value +// --------- ------------ +// 1 scalar +// 2 matrix +// 3 complex scalar +// 4 complex matrix +// 5 string (old style storage) +// 6 range +// 7 string // -// string array -// elements int 4 -// -// for each element: -// length int 4 -// data string length -// -// FILENAME is used for error messages. +// Except for "data type" equal 5 that requires special treatment, these +// old style "data type" value also cause the specific load/save functions +// to be called. FILENAME is used for error messages. std::string read_binary_data (std::istream& is, bool swap, @@ -191,82 +185,30 @@ if (! is.read (X_CAST (char *, &tmp), 1)) goto data_read_error; + // All cases except 255 kept for backwards compatibility switch (tmp) { case 1: - { - if (! is.read (X_CAST (char *, &tmp), 1)) - goto data_read_error; - double dtmp; - read_doubles (is, &dtmp, X_CAST (save_type, tmp), 1, swap, fmt); - if (error_state || ! is) - goto data_read_error; - tc = dtmp; - } + tc = octave_value_typeinfo::lookup_type ("scalar"); break; case 2: - { - FOUR_BYTE_INT nr, nc; - if (! is.read (X_CAST (char *, &nr), 4)) - goto data_read_error; - if (swap) - swap_4_bytes (X_CAST (char *, &nr)); - if (! is.read (X_CAST (char *, &nc), 4)) - goto data_read_error; - if (swap) - swap_4_bytes (X_CAST (char *, &nc)); - if (! is.read (X_CAST (char *, &tmp), 1)) - goto data_read_error; - Matrix m (nr, nc); - double *re = m.fortran_vec (); - int len = nr * nc; - read_doubles (is, re, X_CAST (save_type, tmp), len, swap, fmt); - if (error_state || ! is) - goto data_read_error; - tc = m; - } + tc = octave_value_typeinfo::lookup_type ("matrix"); break; case 3: - { - if (! is.read (X_CAST (char *, &tmp), 1)) - goto data_read_error; - Complex ctmp; - read_doubles (is, X_CAST (double *, &ctmp), - X_CAST (save_type, tmp), 2, swap, fmt); - if (error_state || ! is) - goto data_read_error; - tc = ctmp; - } + tc = octave_value_typeinfo::lookup_type ("complex scalar"); break; case 4: - { - FOUR_BYTE_INT nr, nc; - if (! is.read (X_CAST (char *, &nr), 4)) - goto data_read_error; - if (swap) - swap_4_bytes (X_CAST (char *, &nr)); - if (! is.read (X_CAST (char *, &nc), 4)) - goto data_read_error; - if (swap) - swap_4_bytes (X_CAST (char *, &nc)); - if (! is.read (X_CAST (char *, &tmp), 1)) - goto data_read_error; - ComplexMatrix m (nr, nc); - Complex *im = m.fortran_vec (); - int len = nr * nc; - read_doubles (is, X_CAST (double *, im), - X_CAST (save_type, tmp), 2*len, swap, fmt); - if (error_state || ! is) - goto data_read_error; - tc = m; - } + tc = octave_value_typeinfo::lookup_type ("complex matrix"); break; case 5: { + // XXX FIXME XXXX + // This is cruft, since its for a save type that is old. Maybe + // this is taking backward compatability too far!! FOUR_BYTE_INT len; if (! is.read (X_CAST (char *, &len), 4)) goto data_read_error; @@ -277,66 +219,45 @@ goto data_read_error; s[len] = '\0'; tc = s; + + // Early return, since don't want rest of this function + return retval; } break; case 6: - { - if (! is.read (X_CAST (char *, &tmp), 1)) - goto data_read_error; - double bas, lim, inc; - if (! is.read (X_CAST (char *, &bas), 8)) - goto data_read_error; - if (swap) - swap_8_bytes (X_CAST (char *, &bas)); - if (! is.read (X_CAST (char *, &lim), 8)) - goto data_read_error; - if (swap) - swap_8_bytes (X_CAST (char *, &lim)); - if (! is.read (X_CAST (char *, &inc), 8)) - goto data_read_error; - if (swap) - swap_8_bytes (X_CAST (char *, &inc)); - Range r (bas, lim, inc); - tc = r; - } + tc = octave_value_typeinfo::lookup_type ("range"); break; case 7: + tc = octave_value_typeinfo::lookup_type ("string"); + break; + + case 255: { - FOUR_BYTE_INT elements; - if (! is.read (X_CAST (char *, &elements), 4)) + // Read the saved variable type + FOUR_BYTE_INT len; + if (! is.read (X_CAST (char *, &len), 4)) goto data_read_error; if (swap) - swap_4_bytes (X_CAST (char *, &elements)); - charMatrix chm (elements, 0); - int max_len = 0; - for (int i = 0; i < elements; i++) - { - FOUR_BYTE_INT len; - if (! is.read (X_CAST (char *, &len), 4)) - goto data_read_error; - if (swap) - swap_4_bytes (X_CAST (char *, &len)); - OCTAVE_LOCAL_BUFFER (char, btmp, len+1); - if (! is.read (X_CAST (char *, btmp), len)) - goto data_read_error; - if (len > max_len) - { - max_len = len; - chm.resize (elements, max_len, 0); - } - btmp [len] = '\0'; - chm.insert (btmp, i, 0); - } - tc = octave_value (chm, true); + swap_4_bytes (X_CAST (char *, &len)); + OCTAVE_LOCAL_BUFFER (char, s, len+1); + if (! is.read (X_CAST (char *, s), len)) + goto data_read_error; + s[len] = '\0'; + std::string typ = s; + tc = octave_value_typeinfo::lookup_type (typ); } break; - default: + goto data_read_error; + break; + } + + if (!tc.load_binary (is, swap, fmt)) + { data_read_error: error ("load: trouble reading binary file `%s'", filename.c_str ()); - break; } return retval; @@ -366,118 +287,24 @@ tmp = mark_as_global; os.write (X_CAST (char *, &tmp), 1); - if (tc.is_string ()) - { - tmp = 7; - os.write (X_CAST (char *, &tmp), 1); - FOUR_BYTE_INT nr = tc.rows (); - os.write (X_CAST (char *, &nr), 4); - charMatrix chm = tc.char_matrix_value (); - for (int i = 0; i < nr; i++) - { - FOUR_BYTE_INT len = chm.cols (); - os.write (X_CAST (char *, &len), 4); - std::string tstr = chm.row_as_string (i); - const char *btmp = tstr.data (); - os.write (X_CAST (char *, btmp), len); - } - } - else if (tc.is_range ()) - { - tmp = 6; - os.write (X_CAST (char *, &tmp), 1); - tmp = (char) LS_DOUBLE; - os.write (X_CAST (char *, &tmp), 1); - Range r = tc.range_value (); - double bas = r.base (); - double lim = r.limit (); - double inc = r.inc (); - os.write (X_CAST (char *, &bas), 8); - os.write (X_CAST (char *, &lim), 8); - os.write (X_CAST (char *, &inc), 8); - } - else if (tc.is_real_scalar ()) - { - tmp = 1; - os.write (X_CAST (char *, &tmp), 1); - tmp = (char) LS_DOUBLE; - os.write (X_CAST (char *, &tmp), 1); - double dtmp = tc.double_value (); - os.write (X_CAST (char *, &dtmp), 8); - } - else if (tc.is_real_matrix ()) - { - tmp = 2; - os.write (X_CAST (char *, &tmp), 1); - Matrix m = tc.matrix_value (); - FOUR_BYTE_INT nr = m.rows (); - FOUR_BYTE_INT nc = m.columns (); - os.write (X_CAST (char *, &nr), 4); - os.write (X_CAST (char *, &nc), 4); - int len = nr * nc; - save_type st = LS_DOUBLE; - if (save_as_floats) - { - if (m.too_large_for_float ()) - { - warning ("save: some values too large to save as floats --"); - warning ("save: saving as doubles instead"); - } - else - st = LS_FLOAT; - } - else if (len > 8192) // XXX FIXME XXX -- make this configurable. - { - double max_val, min_val; - if (m.all_integers (max_val, min_val)) - st = get_save_type (max_val, min_val); - } - const double *mtmp = m.data (); - write_doubles (os, mtmp, st, len); - } - else if (tc.is_complex_scalar ()) - { - tmp = 3; - os.write (X_CAST (char *, &tmp), 1); - tmp = (char) LS_DOUBLE; - os.write (X_CAST (char *, &tmp), 1); - Complex ctmp = tc.complex_value (); - os.write (X_CAST (char *, &ctmp), 16); - } - else if (tc.is_complex_matrix ()) - { - tmp = 4; - os.write (X_CAST (char *, &tmp), 1); - ComplexMatrix m = tc.complex_matrix_value (); - FOUR_BYTE_INT nr = m.rows (); - FOUR_BYTE_INT nc = m.columns (); - os.write (X_CAST (char *, &nr), 4); - os.write (X_CAST (char *, &nc), 4); - int len = nr * nc; - save_type st = LS_DOUBLE; - if (save_as_floats) - { - if (m.too_large_for_float ()) - { - warning ("save: some values too large to save as floats --"); - warning ("save: saving as doubles instead"); - } - else - st = LS_FLOAT; - } - else if (len > 4096) // XXX FIXME XXX -- make this configurable. - { - double max_val, min_val; - if (m.all_integers (max_val, min_val)) - st = get_save_type (max_val, min_val); - } - const Complex *mtmp = m.data (); - write_doubles (os, X_CAST (const double *, mtmp), st, 2*len); - } - else - gripe_wrong_type_arg ("save", tc, false); + // 255 flags the new binary format + tmp = 255; + os.write (X_CAST (char *, &tmp), 1); - return os; + // Write the string corresponding to the octave_value type + std::string typ = tc.type_name (); + FOUR_BYTE_INT len = typ.length (); + os.write (X_CAST (char *, &len), 4); + const char *btmp = typ.data (); + os.write (X_CAST (char *, btmp), len); + + // The octave_value of tc is const. Make a copy... + octave_value val = tc; + + // Call specific save function + bool success = val.save_binary (os, save_as_floats); + + return (os && success); } /*
--- a/src/ov-base.cc +++ b/src/ov-base.cc @@ -521,6 +521,53 @@ return retval; } +bool +octave_base_value::save_ascii (std::ostream&, bool&, bool) +{ + gripe_wrong_type_arg ("octave_base_value::save_ascii()", type_name ()); + return false; +} + +bool +octave_base_value::load_ascii (std::istream&) +{ + gripe_wrong_type_arg ("octave_base_value::load_ascii()", type_name ()); + return false; +} + +bool +octave_base_value::save_binary (std::ostream&, bool&) +{ + gripe_wrong_type_arg ("octave_base_value::save_binary()", type_name ()); + return false; +} + +bool +octave_base_value::load_binary (std::istream&, bool, + oct_mach_info::float_format) +{ + gripe_wrong_type_arg ("octave_base_value::load_binary()", type_name ()); + return false; +} + +#if defined (HAVE_HDF5) +bool +octave_base_value::save_hdf5 (hid_t, const char *, bool) +{ + gripe_wrong_type_arg ("octave_base_value::save_binary()", type_name ()); + + return false; +} + +bool +octave_base_value::load_hdf5 (hid_t, const char *, bool) +{ + gripe_wrong_type_arg ("octave_base_value::load_binary()", type_name ()); + + return false; +} +#endif + CONVDECLX (matrix_conv) { return new octave_matrix ();
--- a/src/ov-base.h +++ b/src/ov-base.h @@ -252,6 +252,22 @@ void print_info (std::ostream& os, const std::string& prefix) const; + bool save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf); + + bool load_ascii (std::istream& is); + + bool save_binary (std::ostream& os, bool& save_as_floats); + + bool load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt); + +#if defined (HAVE_HDF5) + bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats); + + bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug); +#endif + private: DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
--- a/src/ov-bool-mat.cc +++ b/src/ov-bool-mat.cc @@ -44,6 +44,11 @@ #include "ov-re-mat.h" #include "pr-output.h" +#include "byte-swap.h" +#include "ls-oct-ascii.h" +#include "ls-hdf5.h" +#include "ls-utils.h" + template class octave_base_matrix<boolNDArray>; DEFINE_OCTAVE_ALLOCATOR (octave_bool_matrix); @@ -148,6 +153,289 @@ current_print_indent_level ()); } +bool +octave_bool_matrix::save_ascii (std::ostream& os, bool& /* infnan_warned */, + bool /* strip_nan_and_inf */) +{ + dim_vector d = dims (); + if (d.length () > 2) + { + NDArray tmp = array_value (); + os << "# ndims: " << d.length () << "\n"; + + for (int i=0; i < d.length (); i++) + os << " " << d (i); + + os << "\n" << tmp; + } + else + { + // Keep this case, rather than use generic code above for backward + // compatiability. Makes load_ascii much more complex!! + os << "# rows: " << rows () << "\n" + << "# columns: " << columns () << "\n"; + + Matrix tmp = matrix_value (); + + os << tmp; + } + + return true; +} + +bool +octave_bool_matrix::load_ascii (std::istream& is) +{ + int mdims = 0; + bool success = true; + std::streampos pos = is.tellg (); + + if (extract_keyword (is, "ndims", mdims, true)) + { + if (mdims >= 0) + { + dim_vector dv; + dv.resize (mdims); + + for (int i = 0; i < mdims; i++) + is >> dv(i); + + NDArray tmp(dv); + is >> tmp; + + if (!is) + { + error ("load: failed to load matrix constant"); + success = false; + } + + boolNDArray btmp (dv); + for (int i = 0; i < btmp.nelem (); i++) + btmp.elem (i) = (tmp.elem (i) != 0.); + + matrix = btmp; + } + else + { + error ("load: failed to extract number of rows and columns"); + success = false; + } + } + else + { + int nr = 0; + int nc = 0; + + // re-read the same line again + is.clear (); + is.seekg (pos); + + if (extract_keyword (is, "rows", nr) && nr >= 0 + && extract_keyword (is, "columns", nc) && nc >= 0) + { + if (nr > 0 && nc > 0) + { + Matrix tmp (nr, nc); + is >> tmp; + if (!is) + { + error ("load: failed to load matrix constant"); + success = false; + } + + boolMatrix btmp (nr,nc); + for (int j = 0; j < nc; j++) + for (int i = 0; i < nr; i++) + btmp.elem (i,j) = (tmp.elem (i, j) != 0.); + + matrix = btmp; + } + else if (nr == 0 || nc == 0) + matrix = boolMatrix (nr, nc); + else + panic_impossible (); + } + else + { + error ("load: failed to extract number of rows and columns"); + success = false; + } + } + + return success; +} + +bool +octave_bool_matrix::save_binary (std::ostream& os, bool& /* save_as_floats */) +{ + + dim_vector d = dims (); + if (d.length() < 1) + return false; + + // Use negative value for ndims to differentiate with old format!! + FOUR_BYTE_INT tmp = - d.length(); + os.write (X_CAST (char *, &tmp), 4); + for (int i=0; i < d.length (); i++) + { + tmp = d(i); + os.write (X_CAST (char *, &tmp), 4); + } + + boolNDArray m = bool_array_value (); + bool *mtmp = m.fortran_vec (); + int nel = m.nelem (); + OCTAVE_LOCAL_BUFFER (char, htmp, nel); + + for (int i = 0; i < nel; i++) + htmp[i] = (mtmp[i] ? 1 : 0); + + os.write (htmp, nel); + + return true; +} + +bool +octave_bool_matrix::load_binary (std::istream& is, bool swap, + oct_mach_info::float_format /* fmt */) +{ + FOUR_BYTE_INT mdims; + if (! is.read (X_CAST (char *, &mdims), 4)) + return false; + if (swap) + swap_4_bytes (X_CAST (char *, &mdims)); + if (mdims >= 0) + return false; + + // mdims is negative for consistency with other matrices, where it is + // negative to allow the positive value to be used for rows/cols for + // backward compatibility + mdims = - mdims; + FOUR_BYTE_INT di; + dim_vector dv; + dv.resize (mdims); + + for (int i = 0; i < mdims; i++) + { + if (! is.read (X_CAST (char *, &di), 4)) + return false; + if (swap) + swap_4_bytes (X_CAST (char *, &di)); + dv(i) = di; + } + + int nel = dv.numel (); + OCTAVE_LOCAL_BUFFER (char, htmp, nel); + if (! is.read (htmp, nel)) + return false; + boolNDArray m(dv); + bool *mtmp = m.fortran_vec (); + for (int i = 0; i < nel; i++) + mtmp[i] = (htmp[i] ? 1 : 0); + matrix = m; + + return true; +} + +#if defined (HAVE_HDF5) +bool +octave_bool_matrix::save_hdf5 (hid_t loc_id, const char *name, + bool /* save_as_floats */) +{ + dim_vector d = dims (); + hsize_t hdims[d.length () > 2 ? d.length () : 3]; + hid_t space_hid = -1, data_hid = -1; + int rank = ( (d (0) == 1) && (d.length () == 2) ? 1 : d.length ()); + bool retval = true; + + boolNDArray m = bool_array_value (); + + // Octave uses column-major, while HDF5 uses row-major ordering + for (int i = 0, j = d.length() - 1; i < d.length (); i++, j--) + hdims[i] = d (j); + + space_hid = H5Screate_simple (rank, hdims, (hsize_t*) 0); + if (space_hid < 0) return false; + + data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_HBOOL, space_hid, + H5P_DEFAULT); + if (data_hid < 0) + { + H5Sclose (space_hid); + return false; + } + + int nel = m.nelem (); + bool *mtmp = m.fortran_vec (); + hbool_t htmp[nel]; + + for (int i = 0; i < nel; i++) + htmp[i] = mtmp[i]; + + retval = H5Dwrite (data_hid, H5T_NATIVE_HBOOL, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void*) htmp) >= 0; + + H5Dclose (data_hid); + H5Sclose (space_hid); + return retval; +} + +bool +octave_bool_matrix::load_hdf5 (hid_t loc_id, const char *name, + bool /* have_h5giterate_bug */) +{ + bool retval = false; + hid_t data_hid = H5Dopen (loc_id, name); + hid_t space_id = H5Dget_space (data_hid); + + hsize_t rank = H5Sget_simple_extent_ndims (space_id); + + if (rank < 1) + { + H5Dclose (data_hid); + return false; + } + + OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank); + OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank); + + H5Sget_simple_extent_dims (space_id, hdims, maxdims); + + dim_vector dv; + + // Octave uses column-major, while HDF5 uses row-major ordering + if (rank == 1) + { + dv.resize (2); + dv(0) = 1; + dv(1) = hdims[0]; + } + else + { + dv.resize (rank); + for (int i = 0, j = rank - 1; i < (int)rank; i++, j--) + dv(j) = hdims[i]; + } + + int nel = dv.numel (); + hbool_t htmp[nel]; + if (H5Dread (data_hid, H5T_NATIVE_HBOOL, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void *) htmp) >= 0) + { + retval = true; + + boolNDArray btmp (dv); + for (int i = 0; i < nel; i++) + btmp.elem (i) = htmp[i]; + + matrix = btmp; + } + + H5Dclose (data_hid); + return retval; +} +#endif + /* ;;; Local Variables: *** ;;; mode: C++ ***
--- a/src/ov-bool-mat.h +++ b/src/ov-bool-mat.h @@ -115,6 +115,22 @@ void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; + bool save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf); + + bool load_ascii (std::istream& is); + + bool save_binary (std::ostream& os, bool& save_as_floats); + + bool load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt); + +#if defined (HAVE_HDF5) + bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats); + + bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug); +#endif + protected: DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-bool.cc +++ b/src/ov-bool.cc @@ -43,6 +43,9 @@ #include "ov-scalar.h" #include "pr-output.h" +#include "ls-oct-ascii.h" +#include "ls-hdf5.h" + template class octave_base_scalar<bool>; DEFINE_OCTAVE_ALLOCATOR (octave_bool); @@ -112,6 +115,110 @@ return octave_value (s); } +bool +octave_bool::save_ascii (std::ostream& os, bool& /* infnan_warned */, + bool /* strip_nan_and_inf */) +{ + double d = double_value (); + + octave_write_double (os, d); + os << "\n"; + + return true; +} + +bool +octave_bool::load_ascii (std::istream& is) +{ + scalar = (octave_read_double (is) != 0.); + + if (!is) + { + error ("load: failed to load scalar constant"); + return false; + } + + return true; +} + +bool +octave_bool::save_binary (std::ostream& os, bool& /* save_as_floats */) +{ + char tmp = (scalar ? 1 : 0); + os.write (X_CAST (char *, &tmp), 1); + + return true; +} + +bool +octave_bool::load_binary (std::istream& is, bool /* swap */, + oct_mach_info::float_format /* fmt */) +{ + char tmp; + if (! is.read (X_CAST (char *, &tmp), 1)) + return false; + scalar = (tmp ? 1 : 0); + return true; +} + +#if defined (HAVE_HDF5) +bool +octave_bool::save_hdf5 (hid_t loc_id, const char *name, + bool /* save_as_floats */) +{ + hsize_t dimens[3]; + hid_t space_hid = -1, data_hid = -1; + bool retval = true; + + space_hid = H5Screate_simple (0, dimens, (hsize_t*) 0); + if (space_hid < 0) return false; + + data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_DOUBLE, space_hid, + H5P_DEFAULT); + if (data_hid < 0) + { + H5Sclose (space_hid); + return false; + } + + double tmp = double_value (); + retval = H5Dwrite (data_hid, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void*) &tmp) >= 0; + + H5Dclose (data_hid); + H5Sclose (space_hid); + return retval; +} + +bool +octave_bool::load_hdf5 (hid_t loc_id, const char *name, + bool /* have_h5giterate_bug */) +{ + hid_t data_hid = H5Dopen (loc_id, name); + hid_t space_id = H5Dget_space (data_hid); + + hsize_t rank = H5Sget_simple_extent_ndims (space_id); + + if (rank != 0) + { + H5Dclose (data_hid); + return false; + } + + double dtmp; + if (H5Dread (data_hid, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void *) &dtmp) < 0) + { + H5Dclose (data_hid); + return false; + } + + scalar = (dtmp != 0.); + H5Dclose (data_hid); + return true; +} +#endif + /* ;;; Local Variables: *** ;;; mode: C++ ***
--- a/src/ov-bool.h +++ b/src/ov-bool.h @@ -110,6 +110,22 @@ octave_value convert_to_str_internal (bool pad, bool force) const; + bool save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf); + + bool load_ascii (std::istream& is); + + bool save_binary (std::ostream& os, bool& save_as_floats); + + bool load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt); + +#if defined (HAVE_HDF5) + bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats); + + bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug); +#endif + private: DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-cell.cc +++ b/src/ov-cell.cc @@ -45,6 +45,12 @@ #include "ov-re-mat.h" #include "ov-scalar.h" +#include "byte-swap.h" +#include "ls-oct-ascii.h" +#include "ls-oct-binary.h" +#include "ls-hdf5.h" +#include "ls-utils.h" + template class octave_base_matrix<Cell>; DEFINE_OCTAVE_ALLOCATOR (octave_cell); @@ -395,6 +401,455 @@ } } +#define CELL_ELT_TAG "<cell-element>" + +bool +octave_cell::save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf) +{ + dim_vector d = dims (); + if (d.length () > 2) + { + os << "# ndims: " << d.length () << "\n"; + + for (int i=0; i < d.length (); i++) + os << " " << d (i); + os << "\n"; + + Cell tmp = cell_value (); + + for (int i = 0; i < d.numel (); i++) + { + octave_value o_val = tmp.elem (i); + + // Recurse to print sub-value. + bool b = save_ascii_data (os, o_val, CELL_ELT_TAG, infnan_warned, + strip_nan_and_inf, 0, 0); + + if (! b) + return os; + } + } + else + { + // Keep this case, rather than use generic code above for backward + // compatiability. Makes load_ascii much more complex!! + os << "# rows: " << rows () << "\n" + << "# columns: " << columns () << "\n"; + + Cell tmp = cell_value (); + + for (int j = 0; j < tmp.cols (); j++) + { + for (int i = 0; i < tmp.rows (); i++) + { + octave_value o_val = tmp.elem (i, j); + + // Recurse to print sub-value. + bool b = save_ascii_data (os, o_val, CELL_ELT_TAG, + infnan_warned, + strip_nan_and_inf, 0, 0); + + if (! b) + return os; + } + + os << "\n"; + } + } + + return true; +} + +bool +octave_cell::load_ascii (std::istream& is) +{ + int mdims = 0; + bool success = true; + std::streampos pos = is.tellg (); + + if (extract_keyword (is, "ndims", mdims, true)) + { + if (mdims >= 0) + { + dim_vector dv; + dv.resize (mdims); + + for (int i = 0; i < mdims; i++) + is >> dv(i); + + Cell tmp(dv); + + for (int i = 0; i < dv.numel (); i++) + { + octave_value t2; + bool dummy; + + // recurse to read cell elements + std::string nm = read_ascii_data (is, std::string (), + dummy, t2, count); + + if (nm == CELL_ELT_TAG) + { + if (is) + tmp.elem (i) = t2; + } + else + { + error ("load: cell array element had unexpected name"); + success = false; + break; + } + } + + if (is) + matrix = tmp; + else + { + error ("load: failed to load matrix constant"); + success = false; + } + } + else + { + error ("load: failed to extract number of rows and columns"); + success = false; + } + + } + else + { + int nr = 0; + int nc = 0; + + // re-read the same line again + is.clear (); + is.seekg (pos); + + if (extract_keyword (is, "rows", nr) && nr >= 0 + && extract_keyword (is, "columns", nc) && nc >= 0) + { + if (nr > 0 && nc > 0) + { + Cell tmp (nr, nc); + + for (int j = 0; j < nc; j++) + { + for (int i = 0; i < nr; i++) + { + octave_value t2; + bool dummy; + + // recurse to read cell elements + std::string nm = read_ascii_data (is, std::string (), + dummy, t2, count); + + if (nm == CELL_ELT_TAG) + { + if (is) + tmp.elem (i, j) = t2; + } + else + { + error ("load: cell array element had unexpected name"); + success = false; + goto cell_read_error; + } + } + } + + cell_read_error: + + if (is) + matrix = tmp; + else + { + error ("load: failed to load cell element"); + success = false; + } + } + else if (nr == 0 || nc == 0) + matrix = Cell (nr, nc); + else + panic_impossible (); + } + else { + error ("load: failed to extract number of rows and columns for cell array"); + success = false; + } + } + + return success; +} + +bool +octave_cell::save_binary (std::ostream& os, bool& save_as_floats) +{ + dim_vector d = dims (); + if (d.length () < 1) + return false; + + // Use negative value for ndims + FOUR_BYTE_INT di = - d.length(); + os.write (X_CAST (char *, &di), 4); + for (int i=0; i < d.length (); i++) + { + di = d(i); + os.write (X_CAST (char *, &di), 4); + } + + Cell tmp = cell_value (); + + for (int i = 0; i < d.numel (); i++) + { + octave_value o_val = tmp.elem (i); + + // Recurse to print sub-value. + bool b = save_binary_data (os, o_val, CELL_ELT_TAG, "", 0, + save_as_floats); + + if (! b) + return false; + } + + return true; +} + +bool +octave_cell::load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt) +{ + bool success = true; + FOUR_BYTE_INT mdims; + if (! is.read (X_CAST (char *, &mdims), 4)) + return false; + if (swap) + swap_4_bytes (X_CAST (char *, &mdims)); + if (mdims >= 0) + return false; + + mdims = -mdims; + FOUR_BYTE_INT di; + dim_vector dv; + dv.resize (mdims); + + for (int i = 0; i < mdims; i++) + { + if (! is.read (X_CAST (char *, &di), 4)) + return false; + if (swap) + swap_4_bytes (X_CAST (char *, &di)); + dv(i) = di; + } + + int nel = dv.numel (); + Cell tmp(dv); + + for (int i = 0; i < nel; i++) + { + octave_value t2; + bool dummy; + std::string doc; + + // recurse to read cell elements + std::string nm = read_binary_data (is, swap, fmt, std::string (), + dummy, t2, doc); + + if (nm == CELL_ELT_TAG) + { + if (is) + tmp.elem (i) = t2; + } + else + { + error ("load: cell array element had unexpected name"); + success = false; + break; + } + } + + if (is) + matrix = tmp; + else + { + error ("load: failed to load matrix constant"); + success = false; + } + + return success; +} + +#if defined (HAVE_HDF5) +bool +octave_cell::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats) +{ + hsize_t dimens[3]; + hid_t space_hid = -1, data_hid = -1, size_hid = -1; + + data_hid = H5Gcreate (loc_id, name, 0); + if (data_hid < 0) return false; + + // Have to save rows/columns since can't have a dataset of groups.... + space_hid = H5Screate_simple (0, dimens, (hsize_t*) 0); + if (space_hid < 0) + { + H5Gclose (data_hid); + return false; + } + + size_hid = H5Dcreate (data_hid, "rows", H5T_NATIVE_INT, space_hid, + H5P_DEFAULT); + if (size_hid < 0) + { + H5Sclose (space_hid); + H5Gclose (data_hid); + return false; + } + + int rc = rows(); + if (! H5Dwrite (size_hid, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void*) &rc) < 0) + { + H5Dclose (size_hid); + H5Sclose (space_hid); + H5Gclose (data_hid); + return false; + } + H5Dclose (size_hid); + + size_hid = H5Dcreate (data_hid, "columns", H5T_NATIVE_INT, space_hid, + H5P_DEFAULT); + if (size_hid < 0) + { + H5Sclose (space_hid); + H5Gclose (data_hid); + return false; + } + + rc = columns(); + if (! H5Dwrite (size_hid, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void*) &rc) < 0) + { + H5Dclose (size_hid); + H5Sclose (space_hid); + H5Gclose (data_hid); + return false; + } + H5Dclose (size_hid); + H5Sclose (space_hid); + + // recursively add each element of the cell to this group + Cell tmp = cell_value (); + + for (int j = 0; j < tmp.cols (); j++) + { + for (int i = 0; i < tmp.rows (); i++) + { + char s[20]; + sprintf (s, "_%d", (i + j * tmp.rows ())); + + if (! add_hdf5_data(data_hid, tmp.elem (i, j), s, "", false, + save_as_floats)) + { + H5Gclose (data_hid); + return false; + } + } + } + + H5Gclose (data_hid); + return true; +} + +bool +octave_cell::load_hdf5 (hid_t loc_id, const char *name, + bool have_h5giterate_bug) +{ + bool retval = false; + hid_t group_id = H5Gopen (loc_id, name); + + if (group_id < 0) + return false; + + hid_t data_hid = H5Dopen (group_id, "rows"); + hid_t space_hid = H5Dget_space (data_hid); + hsize_t rank = H5Sget_simple_extent_ndims (space_hid); + if (rank != 0) + { + H5Dclose(data_hid); + H5Gclose(group_id); + return false; + } + + int nr; + if (H5Dread (data_hid, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void *) &nr) < 0) + { + H5Dclose(data_hid); + H5Gclose(group_id); + return false; + } + H5Dclose (data_hid); + + data_hid = H5Dopen (group_id, "columns"); + space_hid = H5Dget_space (data_hid); + rank = H5Sget_simple_extent_ndims (space_hid); + if (rank != 0) + { + H5Dclose(data_hid); + H5Gclose(group_id); + return false; + } + + int nc; + if (H5Dread (data_hid, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void *) &nc) < 0) + { + H5Dclose(data_hid); + H5Gclose(group_id); + return false; + } + H5Dclose (data_hid); + H5Gclose (group_id); + + hdf5_callback_data dsub; + + herr_t retval2 = -1; + Cell m (nr, nc); + int current_item = 0; + if (have_h5giterate_bug) + current_item = 2; // Skip row/columns items in group + + for (int j = 0; j < nc; j++) + { + for (int i = 0; i < nr; i++) + { + retval2 = H5Giterate (loc_id, name, ¤t_item, + hdf5_read_next_data, &dsub); + if (retval2 <= 0) + break; + + octave_value ov = dsub.tc; + m.elem (i, j) = ov; + + if (have_h5giterate_bug) + current_item++; // H5Giterate returned the last index processed + + } + if (retval2 <= 0) + break; + } + + if (retval2 >= 0) + { + matrix = m; + retval = true; + } + + return retval; +} +#endif + DEFUN (iscell, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} iscell (@var{x})\n\
--- a/src/ov-cell.h +++ b/src/ov-cell.h @@ -110,6 +110,23 @@ void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; + + bool save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf); + + bool load_ascii (std::istream& is); + + bool save_binary (std::ostream& os, bool& save_as_floats); + + bool load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt); + +#if defined (HAVE_HDF5) + bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats); + + bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug); +#endif + private: DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-complex.cc +++ b/src/ov-complex.cc @@ -43,6 +43,9 @@ #include "gripes.h" #include "pr-output.h" +#include "ls-oct-ascii.h" +#include "ls-hdf5.h" + template class octave_base_scalar<Complex>; DEFINE_OCTAVE_ALLOCATOR (octave_complex); @@ -146,6 +149,173 @@ return ComplexNDArray (dim_vector (1, 1), scalar); } +bool +octave_complex::save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf) +{ + Complex c = complex_value (); + + if (strip_nan_and_inf) + { + if (xisnan (c)) + { + error ("only value to plot is NaN"); + return false; + } + else + { + double re = real (c); + double im = imag (c); + + re = xisinf (re) ? (re > 0 ? OCT_RBV : -OCT_RBV) : re; + im = xisinf (im) ? (im > 0 ? OCT_RBV : -OCT_RBV) : im; + + c = Complex (re, im); + + octave_write_complex (os, c); + os << "\n"; + } + } + else + { + if (! infnan_warned && (xisnan (c) || xisinf (c))) + { + warning ("save: Inf or NaN values may not be reloadable"); + infnan_warned = true; + } + + octave_write_complex (os, c); + os << "\n"; + } + + return true; +} + +bool +octave_complex::load_ascii (std::istream& is) +{ + scalar = octave_read_complex (is); + + if (!is) + { + error ("load: failed to load complex scalar constant"); + return false; + } + + return true; +} + + +bool +octave_complex::save_binary (std::ostream& os, bool& /* save_as_floats */) +{ + char tmp = (char) LS_DOUBLE; + os.write (X_CAST (char *, &tmp), 1); + Complex ctmp = complex_value (); + os.write (X_CAST (char *, &ctmp), 16); + + return true; +} + +bool +octave_complex::load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt) +{ + char tmp; + if (! is.read (X_CAST (char *, &tmp), 1)) + return false; + + Complex ctmp; + read_doubles (is, X_CAST (double *, &ctmp), X_CAST (save_type, tmp), 2, + swap, fmt); + if (error_state || ! is) + return false; + + scalar = ctmp; + return true; +} + +#if defined (HAVE_HDF5) +bool +octave_complex::save_hdf5 (hid_t loc_id, const char *name, + bool /* save_as_floats */) +{ + hsize_t dimens[3]; + hid_t space_hid = -1, type_hid = -1, data_hid = -1; + bool retval = true; + + space_hid = H5Screate_simple (0, dimens, (hsize_t*) 0); + if (space_hid < 0) return false; + + type_hid = hdf5_make_complex_type (H5T_NATIVE_DOUBLE); + if (type_hid < 0) + { + H5Sclose (space_hid); + return false; + } + + data_hid = H5Dcreate (loc_id, name, type_hid, space_hid, H5P_DEFAULT); + if (data_hid < 0) + { + H5Sclose (space_hid); + H5Tclose (type_hid); + return false; + } + + Complex tmp = complex_value (); + retval = H5Dwrite (data_hid, type_hid, H5S_ALL, H5S_ALL, H5P_DEFAULT, + (void*) X_CAST (double*, &tmp)) >= 0; + + H5Dclose (data_hid); + H5Tclose (type_hid); + H5Sclose (space_hid); + return retval; +} + +bool +octave_complex::load_hdf5 (hid_t loc_id, const char *name, + bool /* have_h5giterate_bug */) +{ + bool retval = false; + hid_t data_hid = H5Dopen (loc_id, name); + hid_t type_hid = H5Dget_type (data_hid); + + hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE); + + if (! hdf5_types_compatible (type_hid, complex_type)) + { + H5Tclose(complex_type); + H5Dclose (data_hid); + return false; + } + + hid_t space_id = H5Dget_space (data_hid); + hsize_t rank = H5Sget_simple_extent_ndims (space_id); + + if (rank != 0) + { + H5Tclose(complex_type); + H5Sclose (space_id); + H5Dclose (data_hid); + return false; + } + + // complex scalar: + Complex ctmp; + if (H5Dread (data_hid, complex_type, H5S_ALL, H5S_ALL, H5P_DEFAULT, + (void *) X_CAST (double *, &ctmp)) >= 0) + { + retval = true; + scalar = ctmp; + } + + H5Tclose(complex_type); + H5Sclose (space_id); + H5Dclose (data_hid); + return retval; +} +#endif + /* ;;; Local Variables: *** ;;; mode: C++ ***
--- a/src/ov-complex.h +++ b/src/ov-complex.h @@ -98,6 +98,22 @@ void decrement (void) { scalar -= 1.0; } + bool save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf); + + bool load_ascii (std::istream& is); + + bool save_binary (std::ostream& os, bool& save_as_floats); + + bool load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt); + +#if defined (HAVE_HDF5) + bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats); + + bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug); +#endif + private: DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-cx-mat.cc +++ b/src/ov-cx-mat.cc @@ -45,6 +45,11 @@ #include "ov-scalar.h" #include "pr-output.h" +#include "byte-swap.h" +#include "ls-oct-ascii.h" +#include "ls-hdf5.h" +#include "ls-utils.h" + template class octave_base_matrix<ComplexNDArray>; DEFINE_OCTAVE_ALLOCATOR (octave_complex_matrix); @@ -172,6 +177,413 @@ return matrix.matrix_value (); } +static ComplexMatrix +strip_infnan (const ComplexMatrix& m) +{ + int nr = m.rows (); + int nc = m.columns (); + + ComplexMatrix retval (nr, nc); + + int k = 0; + for (int i = 0; i < nr; i++) + { + for (int j = 0; j < nc; j++) + { + Complex c = m (i, j); + if (xisnan (c)) + goto next_row; + else + { + double re = real (c); + double im = imag (c); + + re = xisinf (re) ? (re > 0 ? OCT_RBV : -OCT_RBV) : re; + im = xisinf (im) ? (im > 0 ? OCT_RBV : -OCT_RBV) : im; + + retval (k, j) = Complex (re, im); + } + } + k++; + + next_row: + continue; + } + + if (k > 0) + retval.resize (k, nc); + + return retval; +} + +bool +octave_complex_matrix::save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf) +{ + dim_vector d = dims (); + if (d.length () > 2) + { + ComplexNDArray tmp = complex_array_value (); + + if (strip_nan_and_inf) + { + warning ("save: Can not strip Inf or NaN values"); + warning ("save: Inf or NaN values may not be reloadable"); + infnan_warned = true; + } + else if (! infnan_warned && tmp.any_element_is_inf_or_nan ()) + { + warning ("save: Inf or NaN values may not be reloadable"); + infnan_warned = true; + } + + os << "# ndims: " << d.length () << "\n"; + + for (int i=0; i < d.length (); i++) + os << " " << d (i); + + os << "\n" << tmp; + } + else + { + // Keep this case, rather than use generic code above for backward + // compatiability. Makes load_ascii much more complex!! + os << "# rows: " << rows () << "\n" + << "# columns: " << columns () << "\n"; + + ComplexMatrix tmp = complex_matrix_value (); + + if (strip_nan_and_inf) + tmp = strip_infnan (tmp); + else if (! infnan_warned && tmp.any_element_is_inf_or_nan ()) + { + warning ("save: Inf or NaN values may not be reloadable"); + infnan_warned = true; + } + + os << tmp; + } + + return true; +} + +bool +octave_complex_matrix::load_ascii (std::istream& is) +{ + int mdims = 0; + bool success = true; + std::streampos pos = is.tellg (); + + if (extract_keyword (is, "ndims", mdims, true)) + { + if (mdims >= 0) + { + dim_vector dv; + dv.resize (mdims); + + for (int i = 0; i < mdims; i++) + is >> dv(i); + + ComplexNDArray tmp(dv); + is >> tmp; + + if (!is) + { + error ("load: failed to load matrix constant"); + success = false; + } + matrix = tmp; + } + else + { + error ("load: failed to extract number of rows and columns"); + success = false; + } + } + else + { + int nr = 0; + int nc = 0; + + // re-read the same line again + is.clear (); + is.seekg (pos); + + if (extract_keyword (is, "rows", nr) && nr >= 0 + && extract_keyword (is, "columns", nc) && nc >= 0) + { + if (nr > 0 && nc > 0) + { + ComplexMatrix tmp (nr, nc); + is >> tmp; + if (!is) + { + error ("load: failed to load matrix constant"); + success = false; + } + matrix = tmp; + } + else if (nr == 0 || nc == 0) + matrix = ComplexMatrix (nr, nc); + else + panic_impossible (); + } + else + { + error ("load: failed to extract number of rows and columns"); + success = false; + } + } + + return success; +} + +bool +octave_complex_matrix::save_binary (std::ostream& os, bool& save_as_floats) +{ + dim_vector d = dims (); + if (d.length() < 1) + return false; + + // Use negative value for ndims to differentiate with old format!! + FOUR_BYTE_INT tmp = - d.length(); + os.write (X_CAST (char *, &tmp), 4); + for (int i=0; i < d.length (); i++) + { + tmp = d(i); + os.write (X_CAST (char *, &tmp), 4); + } + + ComplexNDArray m = complex_array_value (); + save_type st = LS_DOUBLE; + if (save_as_floats) + { + if (m.too_large_for_float ()) + { + warning ("save: some values too large to save as floats --"); + warning ("save: saving as doubles instead"); + } + else + st = LS_FLOAT; + } + else if (d.numel () > 4096) // XXX FIXME XXX -- make this configurable. + { + double max_val, min_val; + if (m.all_integers (max_val, min_val)) + st = get_save_type (max_val, min_val); + } + + + const Complex *mtmp = m.data (); + write_doubles (os, X_CAST (const double *, mtmp), st, 2 * d.numel ()); + + return true; +} + +bool +octave_complex_matrix::load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt) +{ + char tmp; + FOUR_BYTE_INT mdims; + if (! is.read (X_CAST (char *, &mdims), 4)) + return false; + if (swap) + swap_4_bytes (X_CAST (char *, &mdims)); + if (mdims < 0) + { + mdims = - mdims; + FOUR_BYTE_INT di; + dim_vector dv; + dv.resize (mdims); + + for (int i = 0; i < mdims; i++) + { + if (! is.read (X_CAST (char *, &di), 4)) + return false; + if (swap) + swap_4_bytes (X_CAST (char *, &di)); + dv(i) = di; + } + + if (! is.read (X_CAST (char *, &tmp), 1)) + return false; + + ComplexNDArray m(dv); + Complex *im = m.fortran_vec (); + read_doubles (is, X_CAST (double *, im), X_CAST (save_type, tmp), + 2 * dv.numel (), swap, fmt); + if (error_state || ! is) + return false; + matrix = m; + } + else + { + FOUR_BYTE_INT nr, nc; + nr = mdims; + if (! is.read (X_CAST (char *, &nc), 4)) + return false; + if (swap) + swap_4_bytes (X_CAST (char *, &nc)); + if (! is.read (X_CAST (char *, &tmp), 1)) + return false; + ComplexMatrix m (nr, nc); + Complex *im = m.fortran_vec (); + int len = nr * nc; + read_doubles (is, X_CAST (double *, im), + X_CAST (save_type, tmp), 2*len, swap, fmt); + if (error_state || ! is) + return false; + matrix = m; + } + return true; +} + +#if defined (HAVE_HDF5) +bool +octave_complex_matrix::save_hdf5 (hid_t loc_id, const char *name, + bool save_as_floats) +{ + dim_vector d = dims (); + hsize_t hdims[d.length () > 2 ? d.length () : 3]; + hid_t space_hid = -1, type_hid = -1, data_hid = -1; + int rank = ( (d (0) == 1) && (d.length () == 2) ? 1 : d.length ()); + bool retval = true; + ComplexNDArray m = complex_array_value (); + + // Octave uses column-major, while HDF5 uses row-major ordering + for (int i = 0, j = d.length() - 1; i < d.length (); i++, j--) + hdims[i] = d (j); + + space_hid = H5Screate_simple (rank, hdims, (hsize_t*) 0); + if (space_hid < 0) return false; + + hid_t save_type_hid = H5T_NATIVE_DOUBLE; + + if (save_as_floats) + { + if (m.too_large_for_float ()) + { + warning ("save: some values too large to save as floats --"); + warning ("save: saving as doubles instead"); + } + else + save_type_hid = H5T_NATIVE_FLOAT; + } +#if HAVE_HDF5_INT2FLOAT_CONVERSIONS + // hdf5 currently doesn't support float/integer conversions + else + { + double max_val, min_val; + + if (m.all_integers (max_val, min_val)) + save_type_hid + = save_type_to_hdf5 (get_save_type (max_val, min_val)); + } +#endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */ + + type_hid = hdf5_make_complex_type (save_type_hid); + if (type_hid < 0) + { + H5Sclose (space_hid); + return false; + } + + data_hid = H5Dcreate (loc_id, name, type_hid, space_hid, H5P_DEFAULT); + if (data_hid < 0) + { + H5Sclose (space_hid); + H5Tclose (type_hid); + return false; + } + + hid_t complex_type_hid = hdf5_make_complex_type (H5T_NATIVE_DOUBLE); + if (complex_type_hid < 0) retval = false; + + if (retval) + { + Complex *mtmp = m.fortran_vec (); + if (H5Dwrite (data_hid, complex_type_hid, H5S_ALL, H5S_ALL, H5P_DEFAULT, + (void*) X_CAST (double *, mtmp)) < 0) + { + H5Tclose (complex_type_hid); + retval = false; + } + } + + H5Tclose (complex_type_hid); + H5Dclose (data_hid); + H5Tclose (type_hid); + H5Sclose (space_hid); + return retval; +} + +bool +octave_complex_matrix::load_hdf5 (hid_t loc_id, const char *name, + bool /* have_h5giterate_bug */) +{ + bool retval = false; + hid_t data_hid = H5Dopen (loc_id, name); + hid_t type_hid = H5Dget_type (data_hid); + + hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE); + + if (! hdf5_types_compatible (type_hid, complex_type)) + { + H5Tclose(complex_type); + H5Dclose (data_hid); + return false; + } + + hid_t space_id = H5Dget_space (data_hid); + + hsize_t rank = H5Sget_simple_extent_ndims (space_id); + + if (rank < 1) + { + H5Tclose(complex_type); + H5Sclose (space_id); + H5Dclose (data_hid); + return false; + } + + OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank); + OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank); + + H5Sget_simple_extent_dims (space_id, hdims, maxdims); + + dim_vector dv; + + // Octave uses column-major, while HDF5 uses row-major ordering + if (rank == 1) + { + dv.resize (2); + dv(0) = 1; + dv(1) = hdims[0]; + } + else + { + dv.resize (rank); + for (int i = 0, j = rank - 1; i < (int)rank; i++, j--) + dv(j) = hdims[i]; + } + + ComplexNDArray m (dv); + Complex *reim = m.fortran_vec (); + if (H5Dread (data_hid, complex_type, H5S_ALL, H5S_ALL, H5P_DEFAULT, + (void *) X_CAST (double *, reim)) >= 0) + { + retval = true; + matrix = m; + } + + H5Tclose(complex_type); + H5Sclose (space_id); + H5Dclose (data_hid); + return retval; +} +#endif + void octave_complex_matrix::print_raw (std::ostream& os, bool pr_as_read_syntax) const
--- a/src/ov-cx-mat.h +++ b/src/ov-cx-mat.h @@ -108,6 +108,22 @@ void decrement (void) { matrix -= Complex (1.0); } + bool save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf); + + bool load_ascii (std::istream& is); + + bool save_binary (std::ostream& os, bool& save_as_floats); + + bool load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt); + +#if defined (HAVE_HDF5) + bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats); + + bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug); +#endif + void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; private:
--- a/src/ov-list.cc +++ b/src/ov-list.cc @@ -39,6 +39,12 @@ #include "ov-list.h" #include "unwind-prot.h" +#include "byte-swap.h" +#include "ls-oct-ascii.h" +#include "ls-oct-binary.h" +#include "ls-hdf5.h" +#include "ls-utils.h" + DEFINE_OCTAVE_ALLOCATOR (octave_list); DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_list, "list", "list"); @@ -495,6 +501,204 @@ return retval; } +bool +octave_list::save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf) +{ + octave_value_list lst = list_value (); + os << "# length: " << lst.length () << "\n"; + + for (int i = 0; i < lst.length (); ++i) + { + // should we use lst.name_tags () to label the elements? + char s[20]; + sprintf (s, "_%d", i); + bool b = save_ascii_data (os, lst (i), s, infnan_warned, + strip_nan_and_inf, 0, 0); + + if (! b) + return false; + } + + return true; +} + +bool +octave_list::load_ascii (std::istream& is) +{ + int len = 0; + bool success = true; + + if (extract_keyword (is, "length", len) && len >= 0) + { + if (len > 0) + { + octave_value_list lst; + + for (int j = 0; j < len; j++) + { + octave_value t2; + bool dummy; + + // recurse to read list elements + std::string nm + = read_ascii_data (is, std::string (), dummy, t2, count); + + if (!is) + break; + + lst.append (t2); + } + + if (is) + data = lst; + else + { + error ("load: failed to load list"); + success = false; + } + } + else if (len == 0 ) + data = Cell (0, 0); + else + panic_impossible (); + } + else { + error ("load: failed to extract number of elements in list"); + success = false; + } + + return success; +} + +bool +octave_list::save_binary (std::ostream& os, bool& save_as_floats) +{ + octave_value_list lst = list_value (); + + FOUR_BYTE_INT len = lst.length(); + os.write (X_CAST (char *, &len), 4); + + for (int i = 0; i < lst.length (); i++) + { + // should we use lst.name_tags () to label the elements? + char s[20]; + sprintf (s, "_%d", i); + + // Recurse to print sub-value. + bool b = save_binary_data (os, lst(i), s, "", 0, save_as_floats); + + if (! b) + return false; + } + + return true; +} + +bool +octave_list::load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt) +{ + FOUR_BYTE_INT len; + if (! is.read (X_CAST (char *, &len), 4)) + return false; + if (swap) + swap_4_bytes (X_CAST (char *, &len)); + + if (len > 0) + { + octave_value_list lst; + + for (int i = 0; i < len; i++) + { + octave_value t2; + bool dummy; + std::string doc; + + // recurse to read list elements + std::string nm = read_binary_data (is, swap, fmt, std::string (), + dummy, t2, doc); + + if (!is) + return false; + + lst.append(t2); + } + + if (is) + data = lst; + else + { + error ("load: failed to load list"); + return false; + } + + } + else if (len == 0 ) + data = Cell (0, 0); + else + return false; + + return true; +} + +#if defined (HAVE_HDF5) +bool +octave_list::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats) +{ + hid_t data_hid = -1; + + data_hid = H5Gcreate (loc_id, name, 0); + if (data_hid < 0) return false; + + // recursively add each element of the list to this group + octave_value_list lst = list_value (); + + for (int i = 0; i < lst.length (); ++i) + { + // should we use lst.name_tags () to label the elements? + char s[20]; + sprintf (s, "_%d", i); + bool retval2 = add_hdf5_data (data_hid, lst (i), s, "", + false, save_as_floats); + if (! retval2) + break; + } + + H5Gclose (data_hid); + return true; +} + +bool +octave_list::load_hdf5 (hid_t loc_id, const char *name, + bool have_h5giterate_bug) +{ + bool retval = false; + + hdf5_callback_data dsub; + + herr_t retval2; + octave_value_list lst; + int current_item = 0; + while ((retval2 = H5Giterate (loc_id, name, ¤t_item, + hdf5_read_next_data, &dsub)) > 0) + { + lst.append (dsub.tc); + + if (have_h5giterate_bug) + current_item++; // H5Giterate returned the last index processed + } + + if (retval2 >= 0) + { + data = lst; + retval = true; + } + + return retval; +} +#endif + /* ;;; Local Variables: *** ;;; mode: C++ ***
--- a/src/ov-list.h +++ b/src/ov-list.h @@ -100,6 +100,22 @@ bool print_name_tag (std::ostream& os, const std::string& name) const; + bool save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf); + + bool load_ascii (std::istream& is); + + bool save_binary (std::ostream& os, bool& save_as_floats); + + bool load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt); + +#if defined (HAVE_HDF5) + bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats); + + bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug); +#endif + protected: // The list of Octave values.
--- a/src/ov-range.cc +++ b/src/ov-range.cc @@ -41,6 +41,10 @@ #include "ov-scalar.h" #include "pr-output.h" +#include "byte-swap.h" +#include "ls-hdf5.h" +#include "ls-utils.h" + DEFINE_OCTAVE_ALLOCATOR (octave_range); DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_range, "range", "double"); @@ -250,6 +254,213 @@ return retval; } +// Skip white space and comments on stream IS. + +static void +skip_comments (std::istream& is) +{ + char c = '\0'; + while (is.get (c)) + { + if (c == ' ' || c == '\t' || c == '\n') + ; // Skip whitespace on way to beginning of next line. + else + break; + } + + for (;;) + { + if (is && (c == '%' || c == '#')) + while (is.get (c) && c != '\n') + ; // Skip to beginning of next line, ignoring everything. + else + break; + } +} + +bool +octave_range::save_ascii (std::ostream& os, bool& /* infnan_warned */, + bool /* strip_nan_and_inf */) +{ + Range r = range_value (); + double base = r.base (); + double limit = r.limit (); + double inc = r.inc (); + + os << "# base, limit, increment\n"; + octave_write_double (os, base); + os << " "; + octave_write_double (os, limit); + os << " "; + octave_write_double (os, inc); + os << "\n"; + + return true; +} + +bool +octave_range::load_ascii (std::istream& is) +{ + // # base, limit, range comment added by save (). + skip_comments (is); + + is >> range; + + if (!is) + { + error ("load: failed to load range constant"); + return false; + } + + return true; +} + +bool +octave_range::save_binary (std::ostream& os, bool& /* save_as_floats */) +{ + char tmp = (char) LS_DOUBLE; + os.write (X_CAST (char *, &tmp), 1); + Range r = range_value (); + double bas = r.base (); + double lim = r.limit (); + double inc = r.inc (); + os.write (X_CAST (char *, &bas), 8); + os.write (X_CAST (char *, &lim), 8); + os.write (X_CAST (char *, &inc), 8); + + return true; +} + +bool +octave_range::load_binary (std::istream& is, bool swap, + oct_mach_info::float_format /* fmt */) +{ + char tmp; + if (! is.read (X_CAST (char *, &tmp), 1)) + return false; + double bas, lim, inc; + if (! is.read (X_CAST (char *, &bas), 8)) + return false; + if (swap) + swap_8_bytes (X_CAST (char *, &bas)); + if (! is.read (X_CAST (char *, &lim), 8)) + return false; + if (swap) + swap_8_bytes (X_CAST (char *, &lim)); + if (! is.read (X_CAST (char *, &inc), 8)) + return false; + if (swap) + swap_8_bytes (X_CAST (char *, &inc)); + Range r (bas, lim, inc); + range = r; + return true; +} + +#if defined (HAVE_HDF5) +// The following subroutines creates an HDF5 representation of the way +// we will store Octave range types (triplets of floating-point numbers). +// NUM_TYPE is the HDF5 numeric type to use for storage (e.g. +// H5T_NATIVE_DOUBLE to save as 'double'). Note that any necessary +// conversions are handled automatically by HDF5. + +static hid_t +hdf5_make_range_type (hid_t num_type) +{ + hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 3); + + H5Tinsert (type_id, "base", 0 * sizeof (double), num_type); + H5Tinsert (type_id, "limit", 1 * sizeof (double), num_type); + H5Tinsert (type_id, "increment", 2 * sizeof (double), num_type); + + return type_id; +} + +bool +octave_range::save_hdf5 (hid_t loc_id, const char *name, + bool /* save_as_floats */) +{ + hsize_t dims[3]; + hid_t space_hid = -1, type_hid = -1, data_hid = -1; + bool retval = true; + + space_hid = H5Screate_simple (0, dims, (hsize_t*) 0); + if (space_hid < 0) return false; + + type_hid = hdf5_make_range_type (H5T_NATIVE_DOUBLE); + if (type_hid < 0) + { + H5Sclose (space_hid); + return false; + } + + data_hid = H5Dcreate (loc_id, name, type_hid, space_hid, H5P_DEFAULT); + if (data_hid < 0) + { + H5Sclose (space_hid); + H5Tclose (type_hid); + return false; + } + + Range r = range_value (); + double range_vals[3]; + range_vals[0] = r.base (); + range_vals[1] = r.limit (); + range_vals[2] = r.inc (); + + retval = H5Dwrite (data_hid, type_hid, H5S_ALL, H5S_ALL, H5P_DEFAULT, + (void*) range_vals) >= 0; + + H5Dclose (data_hid); + H5Tclose (type_hid); + H5Sclose (space_hid); + return retval; +} + +bool +octave_range::load_hdf5 (hid_t loc_id, const char *name, + bool /* have_h5giterate_bug */) +{ + bool retval = false; + hid_t data_hid = H5Dopen (loc_id, name); + hid_t type_hid = H5Dget_type (data_hid); + + hid_t range_type = hdf5_make_range_type (H5T_NATIVE_DOUBLE); + + if (! hdf5_types_compatible (type_hid, range_type)) + { + H5Tclose(range_type); + H5Dclose (data_hid); + return false; + } + + hid_t space_hid = H5Dget_space (data_hid); + hsize_t rank = H5Sget_simple_extent_ndims (space_hid); + + if (rank != 0) + { + H5Tclose(range_type); + H5Sclose (space_hid); + H5Dclose (data_hid); + return false; + } + + double rangevals[3]; + if (H5Dread (data_hid, range_type, H5S_ALL, H5S_ALL, H5P_DEFAULT, + (void *) rangevals) >= 0) + { + retval = true; + Range r (rangevals[0], rangevals[1], rangevals[2]); + range = r; + } + + H5Tclose(range_type); + H5Sclose (space_hid); + H5Dclose (data_hid); + return retval; + +} +#endif + /* ;;; Local Variables: *** ;;; mode: C++ ***
--- a/src/ov-range.h +++ b/src/ov-range.h @@ -171,6 +171,22 @@ bool print_name_tag (std::ostream& os, const std::string& name) const; + bool save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf); + + bool load_ascii (std::istream& is); + + bool save_binary (std::ostream& os, bool& save_as_floats); + + bool load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt); + +#if defined (HAVE_HDF5) + bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats); + + bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug); +#endif + private: Range range;
--- a/src/ov-re-mat.cc +++ b/src/ov-re-mat.cc @@ -49,6 +49,10 @@ #include "pr-output.h" #include "variables.h" +#include "byte-swap.h" +#include "ls-oct-ascii.h" +#include "ls-utils.h" + #if ! defined (UCHAR_MAX) #define UCHAR_MAX 255 #endif @@ -226,6 +230,371 @@ return retval; } +static Matrix +strip_infnan (const Matrix& m) +{ + int nr = m.rows (); + int nc = m.columns (); + + Matrix retval (nr, nc); + + int k = 0; + for (int i = 0; i < nr; i++) + { + for (int j = 0; j < nc; j++) + { + double d = m (i, j); + if (xisnan (d)) + goto next_row; + else + retval (k, j) = xisinf (d) ? (d > 0 ? OCT_RBV : -OCT_RBV) : d; + } + k++; + + next_row: + continue; + } + + if (k > 0) + retval.resize (k, nc); + + return retval; +} + +bool +octave_matrix::save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf) +{ + dim_vector d = dims (); + if (d.length () > 2) + { + NDArray tmp = array_value (); + + if (strip_nan_and_inf) + { + warning ("save: Can not strip Inf or NaN values"); + warning ("save: Inf or NaN values may not be reloadable"); + infnan_warned = true; + } + else if (! infnan_warned && tmp.any_element_is_inf_or_nan ()) + { + warning ("save: Inf or NaN values may not be reloadable"); + infnan_warned = true; + } + + os << "# ndims: " << d.length () << "\n"; + + for (int i=0; i < d.length (); i++) + os << " " << d (i); + + os << "\n" << tmp; + } + else + { + // Keep this case, rather than use generic code above for backward + // compatiability. Makes load_ascii much more complex!! + os << "# rows: " << rows () << "\n" + << "# columns: " << columns () << "\n"; + + Matrix tmp = matrix_value (); + + if (strip_nan_and_inf) + tmp = strip_infnan (tmp); + else if (! infnan_warned && tmp.any_element_is_inf_or_nan ()) + { + warning ("save: Inf or NaN values may not be reloadable"); + infnan_warned = true; + } + + os << tmp; + } + + return true; +} + +bool +octave_matrix::load_ascii (std::istream& is) +{ + int mdims = 0; + bool success = true; + std::streampos pos = is.tellg (); + + if (extract_keyword (is, "ndims", mdims, true)) + { + if (mdims >= 0) + { + dim_vector dv; + dv.resize (mdims); + + for (int i = 0; i < mdims; i++) + is >> dv(i); + + NDArray tmp(dv); + is >> tmp; + + if (!is) + { + error ("load: failed to load matrix constant"); + success = false; + } + matrix = tmp; + } + else + { + error ("load: failed to extract number of rows and columns"); + success = false; + } + } + else + { + int nr = 0; + int nc = 0; + + // re-read the same line again + is.clear (); + is.seekg (pos); + + if (extract_keyword (is, "rows", nr) && nr >= 0 + && extract_keyword (is, "columns", nc) && nc >= 0) + { + if (nr > 0 && nc > 0) + { + Matrix tmp (nr, nc); + is >> tmp; + if (is) + matrix = tmp; + else + { + error ("load: failed to load matrix constant"); + success = false; + } + } + else if (nr == 0 || nc == 0) + matrix = Matrix (nr, nc); + else + panic_impossible (); + } + else + { + error ("load: failed to extract number of rows and columns"); + success = false; + } + } + + return success; +} + +bool +octave_matrix::save_binary (std::ostream& os, bool& save_as_floats) +{ + + dim_vector d = dims (); + if (d.length() < 1) + return false; + + // Use negative value for ndims to differentiate with old format!! + FOUR_BYTE_INT tmp = - d.length(); + os.write (X_CAST (char *, &tmp), 4); + for (int i=0; i < d.length (); i++) + { + tmp = d(i); + os.write (X_CAST (char *, &tmp), 4); + } + + NDArray m = array_value (); + save_type st = LS_DOUBLE; + if (save_as_floats) + { + if (m.too_large_for_float ()) + { + warning ("save: some values too large to save as floats --"); + warning ("save: saving as doubles instead"); + } + else + st = LS_FLOAT; + } + else if (d.numel () > 8192) // XXX FIXME XXX -- make this configurable. + { + double max_val, min_val; + if (m.all_integers (max_val, min_val)) + st = get_save_type (max_val, min_val); + } + + const double *mtmp = m.data (); + write_doubles (os, mtmp, st, d.numel ()); + + return true; +} + +bool +octave_matrix::load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt) +{ + char tmp; + FOUR_BYTE_INT mdims; + if (! is.read (X_CAST (char *, &mdims), 4)) + return false; + if (swap) + swap_4_bytes (X_CAST (char *, &mdims)); + if (mdims < 0) + { + mdims = - mdims; + FOUR_BYTE_INT di; + dim_vector dv; + dv.resize (mdims); + + for (int i = 0; i < mdims; i++) + { + if (! is.read (X_CAST (char *, &di), 4)) + return false; + if (swap) + swap_4_bytes (X_CAST (char *, &di)); + dv(i) = di; + } + + if (! is.read (X_CAST (char *, &tmp), 1)) + return false; + + NDArray m(dv); + double *re = m.fortran_vec (); + read_doubles (is, re, X_CAST (save_type, tmp), dv.numel (), swap, fmt); + if (error_state || ! is) + return false; + matrix = m; + } + else + { + FOUR_BYTE_INT nr, nc; + nr = mdims; + if (! is.read (X_CAST (char *, &nc), 4)) + return false; + if (swap) + swap_4_bytes (X_CAST (char *, &nc)); + if (! is.read (X_CAST (char *, &tmp), 1)) + return false; + Matrix m (nr, nc); + double *re = m.fortran_vec (); + int len = nr * nc; + read_doubles (is, re, X_CAST (save_type, tmp), len, swap, fmt); + if (error_state || ! is) + return false; + matrix = m; + } + return true; +} + +#if defined (HAVE_HDF5) +bool +octave_matrix::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats) +{ + dim_vector d = dims (); + hsize_t hdims[d.length () > 2 ? d.length () : 3]; + hid_t space_hid = -1, data_hid = -1; + int rank = ( (d (0) == 1) && (d.length () == 2) ? 1 : d.length ()); + bool retval = true; + NDArray m = array_value (); + + // Octave uses column-major, while HDF5 uses row-major ordering + for (int i = 0, j = d.length() - 1; i < d.length (); i++, j--) + hdims[i] = d (j); + + space_hid = H5Screate_simple (rank, hdims, (hsize_t*) 0); + if (space_hid < 0) return false; + + hid_t save_type_hid = H5T_NATIVE_DOUBLE; + + if (save_as_floats) + { + if (m.too_large_for_float ()) + { + warning ("save: some values too large to save as floats --"); + warning ("save: saving as doubles instead"); + } + else + save_type_hid = H5T_NATIVE_FLOAT; + } +#if HAVE_HDF5_INT2FLOAT_CONVERSIONS + // hdf5 currently doesn't support float/integer conversions + else + { + double max_val, min_val; + + if (m.all_integers (max_val, min_val)) + save_type_hid + = save_type_to_hdf5 (get_save_type (max_val, min_val)); + } +#endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */ + + data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid, + H5P_DEFAULT); + if (data_hid < 0) + { + H5Sclose (space_hid); + return false; + } + + double *mtmp = m.fortran_vec (); + retval = H5Dwrite (data_hid, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void*) mtmp) >= 0; + + H5Dclose (data_hid); + H5Sclose (space_hid); + return retval; +} + +bool +octave_matrix::load_hdf5 (hid_t loc_id, const char *name, + bool /* have_h5giterate_bug */) +{ + bool retval = false; + hid_t data_hid = H5Dopen (loc_id, name); + hid_t space_id = H5Dget_space (data_hid); + + hsize_t rank = H5Sget_simple_extent_ndims (space_id); + + if (rank < 1) + { + H5Sclose (space_id); + H5Dclose (data_hid); + return false; + } + + OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank); + OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank); + + H5Sget_simple_extent_dims (space_id, hdims, maxdims); + + dim_vector dv; + + // Octave uses column-major, while HDF5 uses row-major ordering + if (rank == 1) + { + dv.resize (2); + dv(0) = 1; + dv(1) = hdims[0]; + } + else + { + dv.resize (rank); + for (int i = 0, j = rank - 1; i < (int)rank; i++, j--) + dv(j) = hdims[i]; + } + + NDArray m (dv); + double *re = m.fortran_vec (); + if (H5Dread (data_hid, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void *) re) >= 0) + { + retval = true; + matrix = m; + } + + H5Sclose (space_id); + H5Dclose (data_hid); + return retval; +} +#endif + void octave_matrix::print_raw (std::ostream& os, bool pr_as_read_syntax) const
--- a/src/ov-re-mat.h +++ b/src/ov-re-mat.h @@ -113,6 +113,22 @@ void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; + bool save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf); + + bool load_ascii (std::istream& is); + + bool save_binary (std::ostream& os, bool& save_as_floats); + + bool load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt); + +#if defined (HAVE_HDF5) + bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats); + + bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug); +#endif + private: DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-scalar.cc +++ b/src/ov-scalar.cc @@ -43,6 +43,9 @@ #include "xdiv.h" #include "xpow.h" +#include "ls-oct-ascii.h" +#include "ls-hdf5.h" + template class octave_base_scalar<double>; DEFINE_OCTAVE_ALLOCATOR (octave_scalar); @@ -115,6 +118,140 @@ return retval; } +bool +octave_scalar::save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf) +{ + double d = double_value (); + + if (strip_nan_and_inf) + { + if (xisnan (d)) + { + error ("only value to plot is NaN"); + return false; + } + else + { + d = xisinf (d) ? (d > 0 ? OCT_RBV : -OCT_RBV) : d; + octave_write_double (os, d); + os << "\n"; + } + } + else + { + if (! infnan_warned && (xisnan (d) || xisinf (d))) + { + warning ("save: Inf or NaN values may not be reloadable"); + infnan_warned = true; + } + + octave_write_double (os, d); + os << "\n"; + } + + return true; +} + +bool +octave_scalar::load_ascii (std::istream& is) +{ + scalar = octave_read_double (is); + if (!is) + { + error ("load: failed to load scalar constant"); + return false; + } + + return true; +} + +bool +octave_scalar::save_binary (std::ostream& os, bool& /* save_as_floats */) +{ + char tmp = (char) LS_DOUBLE; + os.write (X_CAST (char *, &tmp), 1); + double dtmp = double_value (); + os.write (X_CAST (char *, &dtmp), 8); + + return true; +} + +bool +octave_scalar::load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt) +{ + char tmp; + if (! is.read (X_CAST (char *, &tmp), 1)) + return false; + + double dtmp; + read_doubles (is, &dtmp, X_CAST (save_type, tmp), 1, swap, fmt); + if (error_state || ! is) + return false; + + scalar = dtmp; + return true; +} + +#if defined (HAVE_HDF5) +bool +octave_scalar::save_hdf5 (hid_t loc_id, const char *name, + bool /* save_as_floats */) +{ + hsize_t dimens[3]; + hid_t space_hid = -1, data_hid = -1; + bool retval = true; + + space_hid = H5Screate_simple (0, dimens, (hsize_t*) 0); + if (space_hid < 0) return false; + + data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_DOUBLE, space_hid, + H5P_DEFAULT); + if (data_hid < 0) + { + H5Sclose (space_hid); + return false; + } + + double tmp = double_value (); + retval = H5Dwrite (data_hid, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void*) &tmp) >= 0; + + H5Dclose (data_hid); + H5Sclose (space_hid); + return retval; +} + +bool +octave_scalar::load_hdf5 (hid_t loc_id, const char *name, + bool /* have_h5giterate_bug */) +{ + hid_t data_hid = H5Dopen (loc_id, name); + hid_t space_id = H5Dget_space (data_hid); + + hsize_t rank = H5Sget_simple_extent_ndims (space_id); + + if (rank != 0) + { + H5Dclose (data_hid); + return false; + } + + double dtmp; + if (H5Dread (data_hid, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void *) &dtmp) < 0) + { + H5Dclose (data_hid); + return false; + } + + scalar = dtmp; + H5Dclose (data_hid); + return true; +} +#endif + /* ;;; Local Variables: *** ;;; mode: C++ ***
--- a/src/ov-scalar.h +++ b/src/ov-scalar.h @@ -108,6 +108,22 @@ void decrement (void) { --scalar; } + bool save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf); + + bool load_ascii (std::istream& is); + + bool save_binary (std::ostream& os, bool& save_as_floats); + + bool load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt); + +#if defined (HAVE_HDF5) + bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats); + + bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug); +#endif + private: DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-str-mat.cc +++ b/src/ov-str-mat.cc @@ -41,6 +41,11 @@ #include "pr-output.h" #include "pt-mat.h" +#include "byte-swap.h" +#include "ls-oct-ascii.h" +#include "ls-hdf5.h" +#include "ls-utils.h" + DEFINE_OCTAVE_ALLOCATOR (octave_char_matrix_str); DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_char_matrix_str, "string", "char"); @@ -229,6 +234,330 @@ current_print_indent_level (), true); } +bool +octave_char_matrix_str::save_ascii (std::ostream& os, + bool& /* infnan_warned */, + bool /* strip_nan_and_inf */) +{ + charMatrix chm = char_matrix_value (); + int elements = chm.rows (); + os << "# elements: " << elements << "\n"; + for (int i = 0; i < elements; i++) + { + unsigned len = chm.cols (); + os << "# length: " << len << "\n"; + std::string tstr = chm.row_as_string (i, false, true); + const char *tmp = tstr.data (); + if (tstr.length () > len) + panic_impossible (); + os.write (X_CAST (char *, tmp), len); + os << "\n"; + } + + return true; +} + +bool +octave_char_matrix_str::load_ascii (std::istream& is) +{ + int elements; + bool success = true; + std::streampos pos = is.tellg (); + + if (extract_keyword (is, "elements", elements, true)) + { + + if (elements >= 0) + { + // XXX FIXME XXX -- need to be able to get max length + // before doing anything. + + charMatrix chm (elements, 0); + int max_len = 0; + for (int i = 0; i < elements; i++) + { + int len; + if (extract_keyword (is, "length", len) && len >= 0) + { + OCTAVE_LOCAL_BUFFER (char, tmp, len+1); + + if (len > 0 && ! is.read (X_CAST (char *, tmp), len)) + { + error ("load: failed to load string constant"); + success = false; + break; + } + else + { + tmp [len] = '\0'; + if (len > max_len) + { + max_len = len; + chm.resize (elements, max_len, 0); + } + chm.insert (tmp, i, 0); + } + } + else + { + error ("load: failed to extract string length for element %d", + i+1); + success = false; + } + } + + if (! error_state) + matrix = chm; + + } + else + { + error ("load: failed to extract number of string elements"); + success = false; + } + } + else + { + // re-read the same line again + is.clear (); + is.seekg (pos); + + int len; + + if (extract_keyword (is, "length", len) && len >= 0) + { + // This is cruft for backward compatiability, but relatively harmless. + + OCTAVE_LOCAL_BUFFER (char, tmp, len+1); + + if (len > 0 && ! is.read (X_CAST (char *, tmp), len)) + { + error ("load: failed to load string constant"); + } + else + { + tmp [len] = '\0'; + + if (is) + matrix = charMatrix (tmp); + else + error ("load: failed to load string constant"); + } + } + } + + return success; +} + +bool +octave_char_matrix_str::save_binary (std::ostream& os, + bool& /* save_as_floats */) +{ + FOUR_BYTE_INT nr = rows (); + os.write (X_CAST (char *, &nr), 4); + charMatrix chm = char_matrix_value (); + for (int i = 0; i < nr; i++) + { + FOUR_BYTE_INT len = chm.cols (); + os.write (X_CAST (char *, &len), 4); + std::string tstr = chm.row_as_string (i); + const char *btmp = tstr.data (); + os.write (X_CAST (char *, btmp), len); + } + return true; +} + +bool +octave_char_matrix_str::load_binary (std::istream& is, bool swap, + oct_mach_info::float_format /* fmt */) +{ + FOUR_BYTE_INT elements; + if (! is.read (X_CAST (char *, &elements), 4)) + return false; + if (swap) + swap_4_bytes (X_CAST (char *, &elements)); + charMatrix chm (elements, 0); + int max_len = 0; + for (int i = 0; i < elements; i++) + { + FOUR_BYTE_INT len; + if (! is.read (X_CAST (char *, &len), 4)) + return false; + if (swap) + swap_4_bytes (X_CAST (char *, &len)); + OCTAVE_LOCAL_BUFFER (char, btmp, len+1); + if (! is.read (X_CAST (char *, btmp), len)) + return false; + if (len > max_len) + { + max_len = len; + chm.resize (elements, max_len, 0); + } + btmp [len] = '\0'; + chm.insert (btmp, i, 0); + } + + matrix = chm; + return true; +} + +#if defined (HAVE_HDF5) +bool +octave_char_matrix_str::save_hdf5 (hid_t loc_id, const char *name, + bool /* save_as_floats */) +{ + hsize_t dimens[3]; + hid_t space_hid = -1, type_hid = -1, data_hid = -1; + bool retval = true; + + int nr = rows (); + charMatrix chm = char_matrix_value (); + int nc = chm.cols (); + + // create datatype for (null-terminated) string to write from: + type_hid = H5Tcopy (H5T_C_S1); H5Tset_size (type_hid, nc + 1); + if (type_hid < 0) return false; + + dimens[0] = nr; + space_hid = H5Screate_simple (nr > 0 ? 1 : 0, dimens, (hsize_t*) 0); + if (space_hid < 0) + { + H5Tclose (type_hid); + return false; + } + + data_hid = H5Dcreate (loc_id, name, type_hid, space_hid, H5P_DEFAULT); + if (data_hid < 0) + { + H5Sclose (space_hid); + H5Tclose (type_hid); + return false; + } + + OCTAVE_LOCAL_BUFFER (char, s, nr * (nc + 1)); + + for (int i = 0; i < nr; ++i) + { + std::string tstr = chm.row_as_string (i); + strcpy (s + i * (nc+1), tstr.c_str ()); + } + + retval = H5Dwrite (data_hid, type_hid, H5S_ALL, H5S_ALL, H5P_DEFAULT, + (void*) s) >= 0; + + H5Dclose (data_hid); + H5Tclose (type_hid); + H5Sclose (space_hid); + return retval; +} + +bool +octave_char_matrix_str::load_hdf5 (hid_t loc_id, const char *name, + bool /* have_h5giterate_bug */) +{ + hid_t data_hid = H5Dopen (loc_id, name); + hid_t space_hid = H5Dget_space (data_hid); + hsize_t rank = H5Sget_simple_extent_ndims (space_hid); + hid_t type_hid = H5Dget_type (data_hid); + + if (rank == 0) + { + // a single string: + int slen = H5Tget_size (type_hid); + if (slen < 0) + { + H5Tclose (type_hid); + H5Sclose (space_hid); + H5Dclose (data_hid); + return false; + } + else + { + OCTAVE_LOCAL_BUFFER (char, s, slen); + // create datatype for (null-terminated) string + // to read into: + hid_t st_id = H5Tcopy (H5T_C_S1); + H5Tset_size (st_id, slen); + if (H5Dread (data_hid, st_id, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void *) s) < 0) + { + H5Tclose (st_id); + H5Tclose (type_hid); + H5Sclose (space_hid); + H5Dclose (data_hid); + return false; + } + + matrix = charMatrix (s); + + H5Tclose (st_id); + H5Tclose (type_hid); + H5Sclose (space_hid); + H5Dclose (data_hid); + return true; + } + } + else if (rank == 1) + { + // string vector + hsize_t elements, maxdim; + H5Sget_simple_extent_dims (space_hid, &elements, &maxdim); + int slen = H5Tget_size (type_hid); + if (slen < 0) + { + H5Tclose (type_hid); + H5Sclose (space_hid); + H5Dclose (data_hid); + return false; + } + else + { + // hdf5 string arrays store strings of all the + // same physical length (I think), which is + // slightly wasteful, but oh well. + + OCTAVE_LOCAL_BUFFER (char, s, elements * slen); + + // create datatype for (null-terminated) string + // to read into: + hid_t st_id = H5Tcopy (H5T_C_S1); + H5Tset_size (st_id, slen); + + if (H5Dread (data_hid, st_id, H5S_ALL, H5S_ALL, + H5P_DEFAULT, (void *) s) < 0) + { + H5Tclose (st_id); + H5Tclose (type_hid); + H5Sclose (space_hid); + H5Dclose (data_hid); + return false; + } + + charMatrix chm (elements, slen - 1); + for (hsize_t i = 0; i < elements; ++i) + { + chm.insert (s + i*slen, i, 0); + } + + matrix = chm; + + H5Tclose (st_id); + H5Tclose (type_hid); + H5Sclose (space_hid); + H5Dclose (data_hid); + return true; + } + } + else + { + H5Tclose (type_hid); + H5Sclose (space_hid); + H5Dclose (data_hid); + return false; + } +} +#endif + /* ;;; Local Variables: *** ;;; mode: C++ ***
--- a/src/ov-str-mat.h +++ b/src/ov-str-mat.h @@ -124,6 +124,22 @@ void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; + bool save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf); + + bool load_ascii (std::istream& is); + + bool save_binary (std::ostream& os, bool& save_as_floats); + + bool load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt); + +#if defined (HAVE_HDF5) + bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats); + + bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug); +#endif + private: DECLARE_OCTAVE_ALLOCATOR
--- a/src/ov-struct.cc +++ b/src/ov-struct.cc @@ -40,6 +40,12 @@ #include "unwind-prot.h" #include "variables.h" +#include "byte-swap.h" +#include "ls-oct-ascii.h" +#include "ls-oct-binary.h" +#include "ls-hdf5.h" +#include "ls-utils.h" + DEFINE_OCTAVE_ALLOCATOR(octave_struct); DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_struct, "struct", "struct"); @@ -527,6 +533,214 @@ return retval; } +bool +octave_struct::save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf) +{ + Octave_map m = map_value (); + os << "# length: " << m.length () << "\n"; + + Octave_map::iterator i = m.begin (); + while (i != m.end ()) + { + Cell val = map.contents (i); + octave_value tmp = (map.numel () == 1) ? val(0) : + octave_value (val, true); + + bool b = save_ascii_data (os, tmp, m.key (i), infnan_warned, + strip_nan_and_inf, 0, 0); + + if (! b) + return os; + + i++; + } + + return true; +} + +bool +octave_struct::load_ascii (std::istream& is) +{ + int len = 0; + bool success = true; + + if (extract_keyword (is, "length", len) && len >= 0) + { + if (len > 0) + { + Octave_map m (map); + + for (int j = 0; j < len; j++) + { + octave_value t2; + bool dummy; + + // recurse to read cell elements + std::string nm + = read_ascii_data (is, std::string (), dummy, t2, count); + + if (!is) + break; + + m.assign (nm, t2); + } + + if (is) + map = m; + else + { + error ("load: failed to load structure"); + success = false; + } + } + else if (len == 0 ) + map = Octave_map (); + else + panic_impossible (); + } + else { + error ("load: failed to extract number of elements in structure"); + success = false; + } + + return success; +} + +bool +octave_struct::save_binary (std::ostream& os, bool& save_as_floats) +{ + Octave_map m = map_value (); + + FOUR_BYTE_INT len = m.length(); + os.write (X_CAST (char *, &len), 4); + + Octave_map::iterator i = m.begin (); + while (i != m.end ()) + { + Cell val = map.contents (i); + octave_value tmp = (map.numel () == 1) ? val(0) : + octave_value (val, true); + + bool b = save_binary_data (os, tmp, m.key (i), "", 0, save_as_floats); + + if (! b) + return os; + + i++; + } + + return true; +} + +bool +octave_struct::load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt) +{ + bool success = true; + FOUR_BYTE_INT len; + if (! is.read (X_CAST (char *, &len), 4)) + return false; + if (swap) + swap_4_bytes (X_CAST (char *, &len)); + + if (len > 0) + { + Octave_map m (map); + + for (int j = 0; j < len; j++) + { + octave_value t2; + bool dummy; + std::string doc; + + // recurse to read cell elements + std::string nm = read_binary_data (is, swap, fmt, std::string (), + dummy, t2, doc); + + if (!is) + break; + + m.assign (nm, t2); + } + + if (is) + map = m; + else + { + error ("load: failed to load structure"); + success = false; + } + } + else if (len == 0 ) + map = Octave_map (); + else + panic_impossible (); + + return success; +} + +#if defined (HAVE_HDF5) +bool +octave_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats) +{ + hid_t data_hid = -1; + + data_hid = H5Gcreate (loc_id, name, 0); + if (data_hid < 0) return false; + + // recursively add each element of the structure to this group + Octave_map m = map_value (); + Octave_map::iterator i = m.begin (); + while (i != m.end ()) + { + Cell val = map.contents (i); + octave_value tmp = (map.numel () == 1) ? val(0) : + octave_value (val, true); + + bool retval2 = add_hdf5_data (data_hid, tmp, m.key (i), "", false, + save_as_floats); + + if (! retval2) + break; + + i++; + } + + H5Gclose (data_hid); + return true; +} + +bool +octave_struct::load_hdf5 (hid_t loc_id, const char *name, + bool have_h5giterate_bug) +{ + bool retval = false; + + hdf5_callback_data dsub; + + herr_t retval2; + Octave_map m; + int current_item = 0; + while ((retval2 = H5Giterate (loc_id, name, ¤t_item, + hdf5_read_next_data, &dsub)) > 0) + { + m.assign (dsub.name, dsub.tc); + + if (have_h5giterate_bug) + current_item++; // H5Giterate returned the last index processed + } + + if (retval2 >= 0) + { + map = m; + retval = true; + } + + return retval; +} +#endif + /* ;;; Local Variables: *** ;;; mode: C++ ***
--- a/src/ov-struct.h +++ b/src/ov-struct.h @@ -107,6 +107,22 @@ bool print_name_tag (std::ostream& os, const std::string& name) const; + bool save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf); + + bool load_ascii (std::istream& is); + + bool save_binary (std::ostream& os, bool& save_as_floats); + + bool load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt); + +#if defined (HAVE_HDF5) + bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats); + + bool load_hdf5 (hid_t loc_id, const char *name, bool have_h5giterate_bug); +#endif + private: // The associative array used to manage the structure data.
--- a/src/ov-typeinfo.cc +++ b/src/ov-typeinfo.cc @@ -148,6 +148,9 @@ ? instance->do_register_widening_op (t, t_result, f) : false; } +// XXX FIXME XXX -- we should also store all class names and provide a +// way to list them (calling class with nargin == 0?). + int octave_value_typeinfo::do_register_type (const std::string& t_name, const std::string& c_name, @@ -339,6 +342,7 @@ if (nm == types(i)) { retval = vals(i); + retval.make_unique (); break; } }
--- a/src/ov.h +++ b/src/ov.h @@ -33,6 +33,9 @@ #include <string> #include <list> +#if defined (HAVE_HDF5) +#include <hdf5.h> +#endif #include "Range.h" #include "idx-vector.h" @@ -642,6 +645,29 @@ virtual void print_info (std::ostream& os, const std::string& prefix = std::string ()) const; + virtual bool save_ascii (std::ostream& os, bool& infnan_warned, + bool strip_nan_and_inf) + { return rep->save_ascii (os, infnan_warned, strip_nan_and_inf); } + + virtual bool load_ascii (std::istream& is) + { return rep->load_ascii (is); } + + virtual bool save_binary (std::ostream& os, bool& save_as_floats) + { return rep->save_binary (os, save_as_floats); } + + virtual bool load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt) + { return rep->load_binary (is, swap, fmt); } + +#if defined (HAVE_HDF5) + virtual bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats) + { return rep->save_hdf5 (loc_id, name, save_as_floats); } + + virtual bool load_hdf5 (hid_t loc_id, const char *name, + bool have_h5giterate_bug) + { return rep->load_hdf5 (loc_id, name, have_h5giterate_bug); } +#endif + protected: octave_value (const octave_xvalue&) : rep (0) { }