Mercurial > hg > octave-lyh
changeset 8212:ebf6f6a0f9a7
Allow saving/loading of classes. Add saveobj and loadobj methods
author | David Bateman <dbateman@free.fr> |
---|---|
date | Thu, 09 Oct 2008 20:09:13 +0100 |
parents | 851803f7bb4d |
children | d5e08881bba8 |
files | scripts/ChangeLog scripts/general/Makefile.in scripts/general/display.m scripts/general/loadobj.m scripts/general/saveobj.m src/ChangeLog src/ls-mat5.cc src/ls-oct-ascii.h src/ov-class.cc src/ov-class.h |
diffstat | 10 files changed, 475 insertions(+), 129 deletions(-) [+] |
line wrap: on
line diff
--- a/scripts/ChangeLog +++ b/scripts/ChangeLog @@ -24,6 +24,11 @@ * plot/__axis_label__.m: Inherit font properties from axes. +2008-10-09 David Bateman <dbateman@free.fr> + + * general/loadobj.m, general/saveobj.m, general/display: New functions + * general/Makefile.in (SOURCES): Add then here. + 2008-10-08 John W. Eaton <jwe@octave.org> * miscellaneous/fileparts.m: Handle "/file" properly.
--- a/scripts/general/Makefile.in +++ b/scripts/general/Makefile.in @@ -36,17 +36,17 @@ SOURCES = __isequal__.m __splinen__.m accumarray.m arrayfun.m \ bicubic.m bitcmp.m bitget.m bitset.m blkdiag.m cart2pol.m \ cart2sph.m cellidx.m cell2mat.m celldisp.m circshift.m common_size.m \ - cplxpair.m cumtrapz.m dblquad.m deal.m del2.m diff.m flipdim.m fliplr.m \ - flipud.m genvarname.m gradient.m idivide.m ind2sub.m int2str.m \ + cplxpair.m cumtrapz.m dblquad.m deal.m del2.m diff.m display.m flipdim.m \ + fliplr.m flipud.m genvarname.m gradient.m idivide.m ind2sub.m int2str.m \ interp1.m interp1q.m interp2.m interp3.m interpn.m interpft.m \ is_duplicate_entry.m isa.m isdefinite.m isdir.m isequal.m \ isequalwithequalnans.m isscalar.m issquare.m issymmetric.m \ - isvector.m logical.m logspace.m mod.m nargchk.m \ + isvector.m loadobj.m logical.m logspace.m mod.m nargchk.m \ nargoutchk.m nextpow2.m nthroot.m num2str.m perror.m pol2cart.m \ polyarea.m postpad.m prepad.m quadgk.m quadl.m quadv.m randperm.m rat.m \ - rem.m repmat.m rot90.m rotdim.m runlength.m shift.m shiftdim.m sortrows.m \ - sph2cart.m strerror.m structfun.m sub2ind.m subsindex.m triplequad.m \ - trapz.m tril.m triu.m + rem.m repmat.m rot90.m rotdim.m runlength.m saveobj.m shift.m shiftdim.m \ + sortrows.m sph2cart.m strerror.m structfun.m sub2ind.m subsindex.m \ + triplequad.m trapz.m tril.m triu.m DISTFILES = $(addprefix $(srcdir)/, Makefile.in $(SOURCES))
new file mode 100644 --- /dev/null +++ b/scripts/general/display.m @@ -0,0 +1,37 @@ +## Copyright (C) 2008 David Bateman +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or (at +## your option) any later version. +## +## Octave is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} {} display (@var{a}) +## Display the contents of an object. If @var{a} is an object of the +## class "myclass", then @code{display} is called in a case like +## +## @example +## myclass (@dots{}) +## @end example +## +## @noindent +## where Octave is requried to display the contents of a variable of the +## type "myclass". +## +## @seealso{class, subsref, subsasgn} +## @end deftypefn + +function idx = display (a) + error ("display: not defined for class \"%s\"", class(a)); +endfunction
new file mode 100644 --- /dev/null +++ b/scripts/general/loadobj.m @@ -0,0 +1,41 @@ +## Copyright (C) 2008 David Bateman +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or (at +## your option) any later version. +## +## Octave is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{b} =} loadobj (@var{a}) +## Methof of a class to manipulate an object after loading it tfrom a file. +## The function @code{loadobj} is called when the object @var{a} is loaded +## using the @code{load} function. An example of the use of @code{saveobj} +## might be to add fields to an object that don't make sense to be saved. +## For example +## +## @example +## @group +## function b = loadobj (a) +## b = a; +## b.addmssingfield = addfield (b; +## endfunction +## @end group +## @end example +## +## @seealso{saveobj, class} +## @end deftypefn + +function b = loadobj (a) + error ("loadobj: not defined for class \"%s\"", class(a)); +endfunction
new file mode 100644 --- /dev/null +++ b/scripts/general/saveobj.m @@ -0,0 +1,44 @@ +## Copyright (C) 2008 David Bateman +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or (at +## your option) any later version. +## +## Octave is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} {@var{b} =} saveobj (@var{a}) +## Method of a class to manipulate an object prior to saving it to a file. +## The function @code{saveobj} is called when the object @var{a} is saved +## using the @code{save} function. An example of the use of @code{saveobj} +## might be to remove fields of the object that don't make sense to be saved +## or it might be used to ensure that certain fields of the object are +## initialized before the object is saved. For example +## +## @example +## @group +## function b = saveobj (a) +## b = a; +## if (isempty (b.field)) +## b.field = initfield(b); +## endif +## endfunction +## @end group +## @end example +## +## @seealso{loadobj, class} +## @end deftypefn + +function b = saveobj (a) + error ("saveobj: not defined for class \"%s\"", class(a)); +endfunction
--- a/src/ChangeLog +++ b/src/ChangeLog @@ -36,6 +36,27 @@ (F__go_axes_init__): Flag error if handle is deleted during initialization due. +2008-10-09 David Bateman <dbateman@free.fr> + + * ov-class.cc (Octave_map octave_class::map_value (void) const): + Remove. + (bool octave_class::save_ascii (std::ostream&), + bool octave_class::load_ascii (std::istream&), + bool octave_class::save_binary (std::ostream&, bool&), + bool octave_class::save_binary (std::ostream&, bool&), + bool octave_class::save_hdf5 (hid_t, const char *, bool), + bool octave_class::load_hdf5 (hid_t, const char *, bool)): + Allow saving and reloading of classes. + * ov-class. (Octave_map octave_class::map_value (void) const): + Remove. + * ls-mat.cc (std::string read_mat5_binary_element (std::istream&, + const std::string&, bool, bool&, octave_value&), + int save_mat5_element_length (const octave_value&, const std::string&, + bool, bool)): Allow saving and loading of classes. + * ls-oct-ascii.h (template <class T> bool extract_keyword + (std::istream&, const char *, T&, const bool)): Initialize value with + null constructor rather than 0. + 2008-10-07 David Bateman <dbateman@free.fr> * graphics.cc (F__go_delete__): Allow arrays of graphic handles.
--- a/src/ls-mat5.cc +++ b/src/ls-mat5.cc @@ -58,6 +58,7 @@ #include "oct-obj.h" #include "oct-map.h" #include "ov-cell.h" +#include "ov-class.h" #include "ov-fcn-inline.h" #include "pager.h" #include "pt-exp.h" @@ -1099,8 +1100,18 @@ } else { - warning ("load: objects are not implemented"); - goto skip_ahead; + tc = new octave_class (m, classname); + + if (load_path::find_method (classname, "loadobj") != + std::string()) + { + octave_value_list tmp = feval ("loadobj", tc, 1); + + if (! error_state) + tc = tmp(0); + else + goto data_read_error; + } } } else @@ -1794,7 +1805,7 @@ ret += save_mat5_array_length (m.fortran_vec (), m.nelem (), save_as_floats); } - else if (tc.is_map () || tc.is_inline_function ()) + else if (tc.is_map () || tc.is_inline_function () || tc.is_object ()) { int fieldcnt = 0; const Octave_map m = tc.map_value (); @@ -1803,6 +1814,12 @@ if (tc.is_inline_function ()) // length of "inline" is 6 ret += 8 + PAD (6 > max_namelen ? max_namelen : 6); + else if (tc.is_object ()) + { + int classlen = tc.class_name (). length (); + + ret += 8 + PAD (classlen > max_namelen ? max_namelen : classlen); + } for (Octave_map::const_iterator i = m.begin (); i != m.end (); i++) fieldcnt++; @@ -1942,7 +1959,7 @@ flags |= MAT_FILE_STRUCT_CLASS; else if (tc.is_cell ()) flags |= MAT_FILE_CELL_CLASS; - else if (tc.is_inline_function ()) + else if (tc.is_inline_function () || tc.is_object ()) flags |= MAT_FILE_OBJECT_CLASS; else { @@ -2131,12 +2148,11 @@ write_mat5_array (os, ::real (m_cmplx), save_as_floats); write_mat5_array (os, ::imag (m_cmplx), save_as_floats); } - else if (tc.is_map () || tc.is_inline_function()) + else if (tc.is_map () || tc.is_inline_function() || tc.is_object ()) { - const Octave_map m = tc.map_value (); - if (tc.is_inline_function ()) + if (tc.is_inline_function () || tc.is_object ()) { - std::string classname = "inline"; + std::string classname = tc.is_object() ? tc.class_name () : "inline"; int namelen = classname.length (); if (namelen > max_namelen) @@ -2151,6 +2167,20 @@ os.write (paddedname, paddedlength); } + Octave_map m; + + if (tc.is_object () && + load_path::find_method (tc.class_name (), "saveobj") != std::string()) + { + octave_value_list tmp = feval ("saveobj", tc, 1); + if (! error_state) + m = tmp(0).map_value (); + else + goto error_cleanup; + } + else + m = tc.map_value (); + // an Octave structure */ // recursively write each element of the structure {
--- a/src/ls-oct-ascii.h +++ b/src/ls-oct-ascii.h @@ -72,7 +72,7 @@ const bool next_only = false) { bool status = false; - value = 0; + value = T(); char c; while (is.get (c))
--- a/src/ov-class.cc +++ b/src/ov-class.cc @@ -614,14 +614,6 @@ return retval; } -Octave_map -octave_class::map_value (void) const -{ - Octave_map retval; - gripe_wrong_type_arg ("octave_class::map_value()", type_name ()); - return retval; -} - string_vector octave_class::map_keys (void) const { @@ -688,68 +680,31 @@ } } -bool -octave_class::save_ascii (std::ostream&, bool&) -{ - gripe_wrong_type_arg ("octave_class::save_ascii()", type_name ()); - return false; -} - -bool -octave_class::load_ascii (std::istream&) -{ - gripe_wrong_type_arg ("octave_class::load_ascii()", type_name ()); - return false; -} - -bool -octave_class::save_binary (std::ostream&, bool&) -{ - gripe_wrong_type_arg ("octave_class::save_binary()", type_name ()); - return false; -} - -bool -octave_class::load_binary (std::istream&, bool, - oct_mach_info::float_format) +bool +octave_class::save_ascii (std::ostream& os) { - gripe_wrong_type_arg ("octave_class::load_binary()", type_name ()); - return false; -} - -#if defined (HAVE_HDF5) - -bool -octave_class::save_hdf5 (hid_t, const char *, bool) -{ - gripe_wrong_type_arg ("octave_class::save_binary()", type_name ()); - - return false; -} + os << "# classname: " << class_name () << "\n"; + Octave_map m; + if (load_path::find_method (class_name (), "saveobj") != std::string()) + { + octave_value in = new octave_class (*this); + octave_value_list tmp = feval ("saveobj", in, 1); + if (! error_state) + m = tmp(0).map_value (); + else + return false; + } + else + m = map_value (); -bool -octave_class::load_hdf5 (hid_t, const char *, bool) -{ - gripe_wrong_type_arg ("octave_class::load_binary()", type_name ()); - - return false; -} - -#endif - -#if 0 -bool -octave_class::save_ascii (std::ostream& os, bool& infnan_warned) -{ - Octave_map m = map_value (); - os << "# length: " << m.length () << "\n"; + os << "# length: " << m.nfields () << "\n"; Octave_map::iterator i = m.begin (); while (i != m.end ()) { octave_value val = map.contents (i); - bool b = save_ascii_data (os, val, m.key (i), infnan_warned, false, 0); + bool b = save_ascii_data (os, val, m.key (i), false, 0); if (! b) return os; @@ -764,54 +719,82 @@ octave_class::load_ascii (std::istream& is) { octave_idx_type len = 0; + std::string classname; bool success = true; - if (extract_keyword (is, "length", len) && len >= 0) + if (extract_keyword (is, "classname", classname) && classname != "") { - if (len > 0) + if (extract_keyword (is, "length", len) && len >= 0) { - Octave_map m (map); + if (len > 0) + { + Octave_map m (map); - for (octave_idx_type j = 0; j < len; j++) - { - octave_value t2; - bool dummy; + for (octave_idx_type 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, j); + // recurse to read cell elements + std::string nm + = read_ascii_data (is, std::string (), dummy, t2, j); - if (!is) - break; + if (!is) + break; - Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2); + Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2); - if (error_state) - { - error ("load: internal error loading class elements"); - return false; + if (error_state) + { + error ("load: internal error loading class elements"); + return false; + } + + m.assign (nm, tcell); } - m.assign (nm, tcell); - } + if (is) + { + map = m; + c_name = classname; + + if (load_path::find_method (classname, "loadobj") != + std::string()) + { + octave_value in = new octave_class (*this); + octave_value_list tmp = feval ("loadobj", in, 1); - if (is) - map = m; - else - { - error ("load: failed to load class"); - success = false; + if (! error_state) + map = tmp(0).map_value (); + else + success = false; + } + } + else + { + error ("load: failed to load class"); + success = false; + } } + else if (len == 0 ) + { + map = Octave_map (dim_vector (1, 1)); + c_name = classname; + } + else + panic_impossible (); } - else if (len == 0 ) - map = Octave_map (dim_vector (1, 1)); - else - panic_impossible (); + else + { + error ("load: failed to extract number of elements in class"); + success = false; + } } - else { - error ("load: failed to extract number of elements in class"); - success = false; - } + else + { + error ("load: failed to extract name of class"); + success = false; + } return success; } @@ -819,9 +802,25 @@ bool octave_class::save_binary (std::ostream& os, bool& save_as_floats) { - Octave_map m = map_value (); + int32_t classname_len = class_name().length (); + + os.write (reinterpret_cast<char *> (&classname_len), 4); + os << class_name (); - int32_t len = m.length(); + Octave_map m; + if (load_path::find_method (class_name (), "saveobj") != std::string()) + { + octave_value in = new octave_class (*this); + octave_value_list tmp = feval ("saveobj", in, 1); + if (! error_state) + m = tmp(0).map_value (); + else + return false; + } + else + m = map_value (); + + int32_t len = m.nfields(); os.write (reinterpret_cast<char *> (&len), 4); Octave_map::iterator i = m.begin (); @@ -845,6 +844,23 @@ oct_mach_info::float_format fmt) { bool success = true; + + int32_t classname_len; + + is.read (reinterpret_cast<char *> (&classname_len), 4); + if (! is) + return false; + else if (swap) + swap_bytes<4> (&classname_len); + + { + OCTAVE_LOCAL_BUFFER (char, classname, classname_len+1); + classname[classname_len] = '\0'; + if (! is.read (reinterpret_cast<char *> (classname), classname_len)) + return false; + c_name = classname; + } + int32_t len; if (! is.read (reinterpret_cast<char *> (&len), 4)) return false; @@ -880,7 +896,20 @@ } if (is) - map = m; + { + map = m; + + if (load_path::find_method (class_name(), "loadobj") != std::string()) + { + octave_value in = new octave_class (*this); + octave_value_list tmp = feval ("loadobj", in, 1); + + if (! error_state) + map = tmp(0).map_value (); + else + success = false; + } + } else { error ("load: failed to load class"); @@ -900,14 +929,53 @@ bool octave_class::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats) { + hsize_t hdims[3]; + hid_t group_hid = -1; + hid_t type_hid = -1; + hid_t space_hid = -1; + hid_t class_hid = -1; hid_t data_hid = -1; + Octave_map m; + Octave_map::iterator i; + + group_hid = H5Gcreate (loc_id, name, 0); + if (group_hid < 0) + goto error_cleanup; + + // Add the class name to the group + type_hid = H5Tcopy (H5T_C_S1); H5Tset_size (type_hid, c_name.length () + 1); + if (type_hid < 0) + goto error_cleanup; - data_hid = H5Gcreate (loc_id, name, 0); - if (data_hid < 0) return false; + hdims[0] = 0; + space_hid = H5Screate_simple (0 , hdims, 0); + if (space_hid < 0) + goto error_cleanup; + + class_hid = H5Dcreate (group_hid, "classname", type_hid, space_hid, + H5P_DEFAULT); + if (class_hid < 0 || H5Dwrite (class_hid, type_hid, H5S_ALL, H5S_ALL, + H5P_DEFAULT, c_name.c_str ()) < 0) + goto error_cleanup; + + data_hid = H5Gcreate (group_hid, "value", 0); + if (data_hid < 0) + goto error_cleanup; + + if (load_path::find_method (class_name (), "saveobj") != std::string()) + { + octave_value in = new octave_class (*this); + octave_value_list tmp = feval ("saveobj", in, 1); + if (! error_state) + m = tmp(0).map_value (); + else + goto error_cleanup; + } + else + m = map_value (); // recursively add each element of the class to this group - Octave_map m = map_value (); - Octave_map::iterator i = m.begin (); + i = m.begin (); while (i != m.end ()) { octave_value val = map.contents (i); @@ -921,7 +989,22 @@ i++; } - H5Gclose (data_hid); + error_cleanup: + + if (data_hid > 0) + H5Gclose (data_hid); + + if (class_hid > 0) + H5Dclose (class_hid); + + if (space_hid > 0) + H5Sclose (space_hid); + + if (type_hid > 0) + H5Tclose (type_hid); + + if (group_hid > 0) + H5Gclose (group_hid); return true; } @@ -932,22 +1015,87 @@ { bool retval = false; + hid_t group_hid = -1; + hid_t data_hid = -1; + hid_t type_hid = -1; + hid_t type_class_hid = -1; + hid_t space_hid = -1; + hid_t subgroup_hid = -1; + hid_t st_id = -1; + hdf5_callback_data dsub; herr_t retval2 = 0; Octave_map m (dim_vector (1, 1)); int current_item = 0; + hsize_t num_obj = 0; + int slen = 0; + hsize_t rank = 0; + + group_hid = H5Gopen (loc_id, name); + if (group_hid < 0) + goto error_cleanup; + + + data_hid = H5Dopen (group_hid, "classname"); + + if (data_hid < 0) + goto error_cleanup; + + type_hid = H5Dget_type (data_hid); + + type_class_hid = H5Tget_class (type_hid); + + if (type_class_hid != H5T_STRING) + goto error_cleanup; + + space_hid = H5Dget_space (data_hid); + rank = H5Sget_simple_extent_ndims (space_hid); + + if (rank != 0) + goto error_cleanup; + + slen = H5Tget_size (type_hid); + if (slen < 0) + goto error_cleanup; + + // do-while loop here to prevent goto crossing initialization of classname + do + { + OCTAVE_LOCAL_BUFFER (char, classname, slen); + + // create datatype for (null-terminated) string to read into: + st_id = H5Tcopy (H5T_C_S1); + H5Tset_size (st_id, slen); + + if (H5Dread (data_hid, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, + classname) < 0) + { + H5Tclose (st_id); + H5Dclose (data_hid); + H5Gclose (group_hid); + return false; + } + + H5Tclose (st_id); + H5Dclose (data_hid); + data_hid = -1; + + c_name = classname; + } + while (0); + + #ifdef HAVE_H5GGET_NUM_OBJS - hsize_t num_obj = 0; - hid_t group_id = H5Gopen (loc_id, name); - H5Gget_num_objs (group_id, &num_obj); - H5Gclose (group_id); + subgroup_hid = H5Gopen (group_hid, name); + H5Gget_num_objs (subgroup_hid, &num_obj); + H5Gclose (subgroup_hid); while (current_item < static_cast<int> (num_obj) - && (retval2 = H5Giterate (loc_id, name, ¤t_item, + && (retval2 = H5Giterate (group_hid, name, ¤t_item, hdf5_read_next_data, &dsub)) > 0) #else - while ((retval2 = H5Giterate (loc_id, name, ¤t_item, + while ((retval2 = H5Giterate (group_hid, name, ¤t_item, hdf5_read_next_data, &dsub)) > 0) #endif { @@ -970,16 +1118,36 @@ if (retval2 >= 0) { map = m; - retval = true; + + if (load_path::find_method (class_name(), "loadobj") != std::string()) + { + octave_value in = new octave_class (*this); + octave_value_list tmp = feval ("loadobj", in, 1); + + if (! error_state) + { + map = tmp(0).map_value (); + retval = true; + } + else + retval = false; + } + else + retval = true; } + error_cleanup: + if (data_hid > 0) + H5Dclose (data_hid); + + if (data_hid > 0) + H5Gclose (group_hid); + return retval; } #endif -#endif - mxArray * octave_class::as_mxArray (void) const {
--- a/src/ov-class.h +++ b/src/ov-class.h @@ -110,7 +110,7 @@ bool is_object (void) const { return true; } - Octave_map map_value (void) const; + Octave_map map_value (void) const { return map; } string_vector map_keys (void) const; @@ -123,7 +123,7 @@ void print_with_name (std::ostream& os, const std::string& name, bool print_padding = true) const; - bool save_ascii (std::ostream& os, bool& infnan_warned); + bool save_ascii (std::ostream& os); bool load_ascii (std::istream& is);