Skip to content

Commit e36b42c

Browse files
author
Nithin Lakshmisha
committed
Support load and save for classdef objects in MAT-files (bug #45833).
* libinterp/corefcn/load-save.cc (load_save_system::load): Update unwind_action to include "clear_subsystem_handler". (load_save_system::load_vars): Move unwind_action from load_vars to load. (load_save_system::save_vars): Update unwind_action to include "clear_subsystem_handler". Add new block to write MAT-file subsystem data after all variables are saved. * libinterp/corefcn/ls-mat5.cc (read_mat5_binary_file_header): Read subsystem data from MAT-files into "subsystem_handler" object. (read_mat5_binary_element): Read classdef objects as case MAT_FILE_WORKSPACE_CLASS. (save_mat5_element_length): Update to return element length for classdef objects. (save_mat5_binary_element): Update to save classdef objects to file stream. * test/classdef-load-save/classdef-load-save-v6.tst, test/classdef-load-save/classdef-load-save-v7.tst: New tests for load and save with MAT-files in "-v6" and "-v7" file format. * test/classdef-load-save/classdef-load-save-text.tst: Rename file. * test/classdef-load-save/module.mk: Include new test files in build system.
1 parent 3a57832 commit e36b42c

File tree

6 files changed

+954
-94
lines changed

6 files changed

+954
-94
lines changed

libinterp/corefcn/load-save.cc

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -393,9 +393,6 @@ load_save_system::load_vars (std::istream& stream,
393393

394394
octave_idx_type count = 0;
395395

396-
octave::unwind_action
397-
clear_obj_cache ([this] () { clear_mcos_object_cache (); });
398-
399396
for (;;)
400397
{
401398
bool global = false;
@@ -684,8 +681,14 @@ load_save_system::save_vars (const string_vector& argv, int argv_idx,
684681
if (write_header_info)
685682
write_header (os, fmt);
686683

684+
create_subsystem_handler (); // for MAT file formats
685+
687686
octave::unwind_action
688-
clear_obj_cache ([this] () { clear_mcos_object_cache (); });
687+
clear_obj_cache ([this] ()
688+
{
689+
clear_mcos_object_cache ();
690+
clear_subsystem_handler ();
691+
});
689692

690693
if (argv_idx == argc)
691694
{
@@ -735,6 +738,62 @@ load_save_system::save_vars (const string_vector& argv, int argv_idx,
735738
warning ("save: no such variable '%s'", argv[i].c_str ());
736739
}
737740
}
741+
742+
// write subsystem data
743+
if (fmt.type() == MAT5_BINARY || fmt.type() == MAT7_BINARY) // any other formats?
744+
{
745+
subsystem_handler *sh = get_subsystem_handler ();
746+
sh->serialize_to_cell_array ();
747+
// serialized data needs to be saved first to calculate nbytes during save
748+
749+
if (sh->has_serialized_data ())
750+
{
751+
// create new output stream for subsystem data
752+
std::ostringstream subsys_stream;
753+
754+
const char *header;
755+
if (mach_info::words_big_endian ())
756+
header = "\x01\x00\x4d\x49\x00\x00\x00\x00";
757+
else
758+
header = "\x00\x01\x49\x4d\x00\x00\x00\x00";
759+
subsys_stream.write (header, 8);
760+
761+
// create FileWrapper__ object to register as MAT_FILE_WORKSPACE_CLASS
762+
octave::cdef_manager& cdm = octave::__get_cdef_manager__ ();
763+
octave::cdef_class filewrapper_class
764+
= cdm.make_class ("FileWrapper__", std::list<octave::cdef_class> ());
765+
octave_value filewrapper_obj
766+
= filewrapper_class.construct (octave_value_list (), true);
767+
768+
octave_scalar_map subsys_map;
769+
subsys_map.assign ("MCOS", filewrapper_obj);
770+
// TODO: include other type systems "java" and "handle"
771+
772+
std::string help;
773+
do_save (subsys_stream, subsys_map, "", help, false, MAT5_BINARY,
774+
save_as_floats);
775+
// don't use zlib compression on subsys_stream
776+
777+
// convert stream to uint8NDArray
778+
// FIXME: How to optimize?
779+
const std::string& stream_data = subsys_stream.str();
780+
octave_idx_type data_size = stream_data.size ();
781+
uint8NDArray subsys_data (dim_vector (1, data_size));
782+
std::memcpy (subsys_data.rwdata(), stream_data.data(), data_size);
783+
784+
// save the uint8NDArray to original stream without variable name
785+
octave_value subsys_value (subsys_data);
786+
std::streampos subsys_offset = os.tellp ();
787+
do_save (os, subsys_value, "", help, false, fmt, save_as_floats);
788+
789+
// update subsystem offset in MAT-file header
790+
std::streampos current_pos = os.tellp ();
791+
os.seekp (116);
792+
uint64_t offset_val = static_cast<uint64_t> (subsys_offset);
793+
os.write (reinterpret_cast<const char*> (&offset_val), 8);
794+
os.seekp (current_pos);
795+
}
796+
}
738797
}
739798

740799
void
@@ -1198,6 +1257,15 @@ load_save_system::load (const octave_value_list& args, int nargout)
11981257
bool list_only = false;
11991258
bool verbose = false;
12001259

1260+
create_subsystem_handler (); // for MAT file formats
1261+
1262+
octave::unwind_action
1263+
clear_obj_cache ([this] ()
1264+
{
1265+
clear_mcos_object_cache ();
1266+
clear_subsystem_handler ();
1267+
});
1268+
12011269
for (; i < argc; i++)
12021270
{
12031271
if (argv[i] == "-text" || argv[i] == "-t")

0 commit comments

Comments
 (0)