# HG changeset patch # User jwe # Date 1198881143 0 # Node ID 5215422865e0f37f550c6f4265eff90388d53be9 # Parent e70789e0cd9272720f266acee6abfef02e656f11 [project @ 2007-12-28 22:31:35 by jwe] diff -r e70789e0cd92 -r 5215422865e0 src/OPERATORS/op-class.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/OPERATORS/op-class.cc Fri Dec 28 22:32:23 2007 +0000 @@ -0,0 +1,168 @@ +/* + +Copyright (C) 2007 John W. Eaton + +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 2, 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, write to the Free +Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "oct-time.h" + +#include "gripes.h" +#include "load-path.h" +#include "oct-obj.h" +#include "ov.h" +#include "ov-class.h" +#include "ov-typeinfo.h" +#include "ops.h" +#include "symtab.h" +#include "parse.h" + +// class ops. + +#define DEF_CLASS_UNOP(name) \ + static octave_value \ + oct_unop_ ## name (const octave_value& a) \ + { \ + octave_value retval; \ + \ + std::string class_name = a.class_name (); \ + \ + octave_value meth = symbol_table::find_method (#name, class_name); \ + \ + if (meth.is_defined ()) \ + { \ + octave_value_list args; \ + \ + args(0) = a; \ + \ + octave_value_list tmp = feval (meth.function_value (), args, 1); \ + \ + if (tmp.length () > 0) \ + retval = tmp(0); \ + } \ + else \ + error ("%s method not defined for %s class", \ + #name, class_name.c_str ()); \ + \ + return retval; \ + } + +DEF_CLASS_UNOP (not) +DEF_CLASS_UNOP (uplus) +DEF_CLASS_UNOP (uminus) +DEF_CLASS_UNOP (transpose) +DEF_CLASS_UNOP (ctranspose) + +// FIXME -- we need to handle precedence in the binop function. + +#define DEF_CLASS_BINOP(name) \ + static octave_value \ + oct_binop_ ## name (const octave_value& a1, const octave_value& a2) \ + { \ + octave_value retval; \ + \ + std::string dispatch_type \ + = a1.is_object () ? a1.class_name () : a2.class_name (); \ + \ + octave_value meth = symbol_table::find_method (#name, dispatch_type); \ + \ + if (meth.is_defined ()) \ + { \ + octave_value_list args; \ + \ + args(1) = a2; \ + args(0) = a1; \ + \ + octave_value_list tmp = feval (meth.function_value (), args, 1); \ + \ + if (tmp.length () > 0) \ + retval = tmp(0); \ + } \ + else \ + error ("%s method not defined for %s class", \ + #name, dispatch_type.c_str ()); \ + \ + return retval; \ + } + +DEF_CLASS_BINOP (plus) +DEF_CLASS_BINOP (minus) +DEF_CLASS_BINOP (mtimes) +DEF_CLASS_BINOP (mrdivide) +DEF_CLASS_BINOP (mpower) +DEF_CLASS_BINOP (mldivide) +DEF_CLASS_BINOP (lt) +DEF_CLASS_BINOP (le) +DEF_CLASS_BINOP (eq) +DEF_CLASS_BINOP (ge) +DEF_CLASS_BINOP (gt) +DEF_CLASS_BINOP (ne) +DEF_CLASS_BINOP (times) +DEF_CLASS_BINOP (rdivide) +DEF_CLASS_BINOP (power) +DEF_CLASS_BINOP (ldivide) +DEF_CLASS_BINOP (and) +DEF_CLASS_BINOP (or) + +#define INSTALL_CLASS_UNOP(op, f) \ + octave_value_typeinfo::register_unary_class_op \ + (octave_value::op, oct_unop_ ## f) + +#define INSTALL_CLASS_BINOP(op, f) \ + octave_value_typeinfo::register_binary_class_op \ + (octave_value::op, oct_binop_ ## f) + +void +install_class_ops (void) +{ + INSTALL_CLASS_UNOP (op_not, not); + INSTALL_CLASS_UNOP (op_uplus, uplus); + INSTALL_CLASS_UNOP (op_uminus, uminus); + INSTALL_CLASS_UNOP (op_transpose, transpose); + INSTALL_CLASS_UNOP (op_hermitian, ctranspose); + + INSTALL_CLASS_BINOP (op_add, plus); + INSTALL_CLASS_BINOP (op_sub, minus); + INSTALL_CLASS_BINOP (op_mul, mtimes); + INSTALL_CLASS_BINOP (op_div, mrdivide); + INSTALL_CLASS_BINOP (op_pow, mpower); + INSTALL_CLASS_BINOP (op_ldiv, mldivide); + INSTALL_CLASS_BINOP (op_lt, lt); + INSTALL_CLASS_BINOP (op_le, le); + INSTALL_CLASS_BINOP (op_eq, eq); + INSTALL_CLASS_BINOP (op_ge, ge); + INSTALL_CLASS_BINOP (op_gt, gt); + INSTALL_CLASS_BINOP (op_ne, ne); + INSTALL_CLASS_BINOP (op_el_mul, times); + INSTALL_CLASS_BINOP (op_el_div, rdivide); + INSTALL_CLASS_BINOP (op_el_pow, power); + INSTALL_CLASS_BINOP (op_el_ldiv, ldivide); + INSTALL_CLASS_BINOP (op_el_and, and); + INSTALL_CLASS_BINOP (op_el_or, or); +} + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/ diff -r e70789e0cd92 -r 5215422865e0 src/ov-class.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ov-class.cc Fri Dec 28 22:32:23 2007 +0000 @@ -0,0 +1,1199 @@ +/* + +Copyright (C) 2007 John W. Eaton + +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 2, 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, write to the Free +Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "Array-util.h" +#include "byte-swap.h" + +#include "Cell.h" +#include "defun.h" +#include "error.h" +#include "gripes.h" +#include "load-path.h" +#include "ls-hdf5.h" +#include "ls-oct-ascii.h" +#include "ls-oct-binary.h" +#include "ls-utils.h" +#include "oct-lvalue.h" +#include "ov-class.h" +#include "ov-fcn.h" +#include "pager.h" +#include "parse.h" +#include "pr-output.h" +#include "toplev.h" +#include "unwind-prot.h" +#include "variables.h" + +DEFINE_OCTAVE_ALLOCATOR(octave_class); + +int octave_class::t_id (-1); + +const std::string octave_class::t_name ("class"); + +void +octave_class::register_type (void) +{ + t_id = octave_value_typeinfo::register_type + (octave_class::t_name, "", octave_value (new octave_class ())); +} + +Cell +octave_class::dotref (const octave_value_list& idx) +{ + Cell retval; + + assert (idx.length () == 1); + + std::string nm = idx(0).string_value (); + + Octave_map::const_iterator p = map.seek (nm); + + if (p != map.end ()) + retval = map.contents (p); + else + error ("class has no member `%s'", nm.c_str ()); + + return retval; +} + +static void +gripe_invalid_index (void) +{ + error ("invalid index for class"); +} + +static void +gripe_invalid_index_for_assignment (void) +{ + error ("invalid index for class assignment"); +} + +static void +gripe_invalid_index_type (const std::string& nm, char t) +{ + error ("%s cannot be indexed with %c", nm.c_str (), t); +} + +static void +gripe_failed_assignment (void) +{ + error ("assignment to class element failed"); +} + +static inline octave_value_list +sanitize (const octave_value_list& ovl) +{ + octave_value_list retval = ovl; + + for (octave_idx_type i = 0; i < ovl.length (); i++) + { + if (retval(i).is_magic_colon ()) + retval(i) = ":"; + } + + return retval; +} + +static inline octave_value +make_idx_args (const std::string& type, + const std::list& idx, + const std::string& who) +{ + octave_value retval; + + size_t len = type.length (); + + if (len == idx.size ()) + { + Cell type_field (len, 1); + Cell subs_field (len, 1); + + std::list::const_iterator p = idx.begin (); + + for (size_t i = 0; i < len; i++) + { + char t = type[i]; + + switch (t) + { + case '(': + type_field(i) = "()"; + subs_field(i) = Cell (sanitize (*p++)); + break; + + case '{': + type_field(i) = "{}"; + subs_field(i) = Cell (sanitize (*p++)); + break; + + case '.': + { + type_field(i) = "."; + + octave_value_list vlist = *p++; + + if (vlist.length () == 1) + { + octave_value val = vlist(0); + + if (val.is_string ()) + subs_field(i) = val; + else + { + error ("expecting character string argument for `.' index"); + return retval; + } + } + else + { + error ("expecting single argument for `.' index"); + return retval; + } + } + break; + + default: + panic_impossible (); + break; + } + } + + Octave_map m; + + m.assign ("type", type_field); + m.assign ("subs", subs_field); + + retval = m; + } + else + error ("invalid index for %s", who.c_str ()); + + return retval; +} + +octave_value_list +octave_class::subsref (const std::string& type, + const std::list& idx, + int nargout) +{ + octave_value_list retval; + + if (in_class_method ()) + { + // FIXME -- this block of code is the same as the body of + // octave_struct::subsref. Maybe it could be shared instead of + // duplicated. + + int skip = 1; + + switch (type[0]) + { + case '(': + { + if (type.length () > 1 && type[1] == '.') + { + std::list::const_iterator p = idx.begin (); + octave_value_list key_idx = *++p; + + Cell tmp = dotref (key_idx); + + if (! error_state) + { + Cell t = tmp.index (idx.front ()); + + retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true); + + // We handled two index elements, so tell + // next_subsref to skip both of them. + + skip++; + } + } + else + retval(0) = map.index (idx.front ()); + } + break; + + case '.': + { + if (map.numel() > 0) + { + Cell t = dotref (idx.front ()); + + retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true); + } + } + break; + + case '{': + gripe_invalid_index_type (type_name (), type[0]); + break; + + default: + panic_impossible (); + } + + // FIXME -- perhaps there should be an + // octave_value_list::next_subsref member function? See also + // octave_user_function::subsref. + + if (idx.size () > 1) + retval = retval(0).next_subsref (nargout, type, idx, skip); + } + else + { + octave_value meth = symbol_table::find_method ("subsref", class_name ()); + + if (meth.is_defined ()) + { + octave_value_list args; + + args(1) = make_idx_args (type, idx, "subsref"); + + if (error_state) + return octave_value_list (); + + count++; + args(0) = octave_value (this); + + return feval (meth.function_value (), args, nargout); + } + else + { + if (type.length () == 1 && type[0] == '(') + retval(0) = octave_value (map.index (idx.front ()), class_name ()); + else + gripe_invalid_index (); + } + } + + return retval; +} + +octave_value +octave_class::numeric_conv (const Cell& val, const std::string& type) +{ + octave_value retval; + + if (val.length () == 1) + { + retval = val(0); + + if (type.length () > 0 && type[0] == '.' && ! retval.is_map ()) + retval = Octave_map (); + } + else + gripe_invalid_index_for_assignment (); + + return retval; +} + +octave_value +octave_class::subsasgn (const std::string& type, + const std::list& idx, + const octave_value& rhs) +{ + octave_value retval; + + if (in_class_method ()) + { + // FIXME -- this block of code is the same as the body of + // octave_struct::subsasgn. Maybe it could be shared instead of + // duplicated. + + int n = type.length (); + + octave_value t_rhs = rhs; + + if (n > 1 && ! (type.length () == 2 && type[0] == '(' && type[1] == '.')) + { + switch (type[0]) + { + case '(': + { + if (type.length () > 1 && type[1] == '.') + { + std::list::const_iterator p = idx.begin (); + octave_value_list t_idx = *p; + + octave_value_list key_idx = *++p; + + assert (key_idx.length () == 1); + + std::string key = key_idx(0).string_value (); + + octave_value u; + + if (! map.contains (key)) + u = octave_value::empty_conv (type.substr (2), rhs); + else + { + Cell map_val = map.contents (key); + + Cell map_elt = map_val.index (idx.front (), true); + + u = numeric_conv (map_elt, type.substr (2)); + } + + if (! error_state) + { + std::list next_idx (idx); + + // We handled two index elements, so subsasgn to + // needs to skip both of them. + + next_idx.erase (next_idx.begin ()); + next_idx.erase (next_idx.begin ()); + + u.make_unique (); + + t_rhs = u.subsasgn (type.substr (2), next_idx, rhs); + } + } + else + gripe_invalid_index_for_assignment (); + } + break; + + case '.': + { + octave_value_list key_idx = idx.front (); + + assert (key_idx.length () == 1); + + std::string key = key_idx(0).string_value (); + + octave_value u; + + if (! map.contains (key)) + u = octave_value::empty_conv (type.substr (1), rhs); + else + { + Cell map_val = map.contents (key); + + u = numeric_conv (map_val, type.substr (1)); + } + + if (! error_state) + { + std::list next_idx (idx); + + next_idx.erase (next_idx.begin ()); + + u.make_unique (); + + t_rhs = u.subsasgn (type.substr (1), next_idx, rhs); + } + } + break; + + case '{': + gripe_invalid_index_type (type_name (), type[0]); + break; + + default: + panic_impossible (); + } + } + + if (! error_state) + { + switch (type[0]) + { + case '(': + { + if (n > 1 && type[1] == '.') + { + std::list::const_iterator p = idx.begin (); + octave_value_list key_idx = *++p; + + assert (key_idx.length () == 1); + + std::string key = key_idx(0).string_value (); + + if (! error_state) + { + map.assign (idx.front (), key, t_rhs); + + if (! error_state) + { + count++; + retval = octave_value (this); + } + else + gripe_failed_assignment (); + } + else + gripe_failed_assignment (); + } + else + { + if (t_rhs.is_map()) + { + Octave_map rhs_map = t_rhs.map_value (); + + if (! error_state) + { + map.assign (idx.front (), rhs_map); + + if (! error_state) + { + count++; + retval = octave_value (this); + } + else + gripe_failed_assignment (); + } + else + error ("invalid class assignment"); + } + else + { + if (t_rhs.is_empty()) + { + map.maybe_delete_elements (idx.front()); + + if (! error_state) + { + count++; + retval = octave_value (this); + } + else + gripe_failed_assignment (); + } + else + error ("invalid class assignment"); + } + } + } + break; + + case '.': + { + octave_value_list key_idx = idx.front (); + + assert (key_idx.length () == 1); + + std::string key = key_idx(0).string_value (); + + map.assign (key, t_rhs); + + if (! error_state) + { + count++; + retval = octave_value (this); + } + else + gripe_failed_assignment (); + } + break; + + case '{': + gripe_invalid_index_type (type_name (), type[0]); + break; + + default: + panic_impossible (); + } + } + else + gripe_failed_assignment (); + } + else + { + octave_value meth = symbol_table::find_method ("subsasgn", class_name ()); + + if (meth.is_defined ()) + { + octave_value_list args; + + args(2) = rhs; + + args(1) = make_idx_args (type, idx, "subsasgn"); + + if (error_state) + return octave_value_list (); + + count++; + args(0) = octave_value (this); + + octave_value_list tmp = feval (meth.function_value (), args); + + // FIXME -- should the subsasgn method be able to return + // more than one value? + + if (tmp.length () > 1) + error ("expecting single return value from @%s/subsasgn", + class_name().c_str ()); + else + retval = tmp(0); + + } + else + error ("no subsasgn method defined for class %s", + class_name().c_str ()); + } + + return retval; +} + +size_t +octave_class::byte_size (void) const +{ + // Neglect the size of the fieldnames. + + size_t retval = 0; + + for (Octave_map::const_iterator p = map.begin (); p != map.end (); p++) + { + std::string key = map.key (p); + + octave_value val = octave_value (map.contents (p)); + + retval += val.byte_size (); + } + + 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 +{ + string_vector retval; + gripe_wrong_type_arg ("octave_class::map_keys()", type_name ()); + return retval; +} + +void +octave_class::print (std::ostream& os, bool) const +{ + print_raw (os); +} + +void +octave_class::print_raw (std::ostream& os, bool) const +{ + unwind_protect::begin_frame ("octave_class_print"); + + unwind_protect_int (Vstruct_levels_to_print); + + indent (os); + os << " "; + newline (os); + + unwind_protect::run_frame ("octave_class_print"); +} + +bool +octave_class::print_name_tag (std::ostream& os, const std::string& name) const +{ + bool retval = false; + + indent (os); + os << name << " ="; + newline (os); + newline (os); + + return retval; +} + +void +octave_class::print_with_name (std::ostream&, const std::string& name, + bool) const +{ + if (! (evaluating_function_body && Vsilent_functions)) + { + octave_value fcn = symbol_table::find_method ("display", class_name ()); + + if (fcn.is_defined ()) + { + octave_value_list args; + + args(0) = octave_value (clone (), 1); + + string_vector arg_names (1); + + arg_names[0] = name; + + args.stash_name_tags (arg_names); + + feval (fcn.function_value (), args); + } + } +} + +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) +{ + 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; +} + +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"; + + 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); + + if (! b) + return os; + + i++; + } + + return true; +} + +bool +octave_class::load_ascii (std::istream& is) +{ + octave_idx_type len = 0; + bool success = true; + + if (extract_keyword (is, "length", len) && len >= 0) + { + if (len > 0) + { + Octave_map m (map); + + 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); + + if (!is) + break; + + Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2); + + if (error_state) + { + error ("load: internal error loading class elements"); + return false; + } + + m.assign (nm, tcell); + } + + if (is) + map = m; + else + { + error ("load: failed to load class"); + success = false; + } + } + 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; + } + + return success; +} + +bool +octave_class::save_binary (std::ostream& os, bool& save_as_floats) +{ + Octave_map m = map_value (); + + int32_t len = m.length(); + os.write (reinterpret_cast (&len), 4); + + Octave_map::iterator i = m.begin (); + while (i != m.end ()) + { + octave_value val = map.contents (i); + + bool b = save_binary_data (os, val, m.key (i), "", 0, save_as_floats); + + if (! b) + return os; + + i++; + } + + return true; +} + +bool +octave_class::load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt) +{ + bool success = true; + int32_t len; + if (! is.read (reinterpret_cast (&len), 4)) + return false; + if (swap) + swap_bytes<4> (&len); + + if (len > 0) + { + Octave_map m (map); + + for (octave_idx_type 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; + + Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2); + + if (error_state) + { + error ("load: internal error loading class elements"); + return false; + } + + m.assign (nm, tcell); + } + + if (is) + map = m; + else + { + error ("load: failed to load class"); + success = false; + } + } + else if (len == 0 ) + map = Octave_map (dim_vector (1, 1)); + else + panic_impossible (); + + return success; +} + +#if defined (HAVE_HDF5) + +bool +octave_class::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 class to this group + Octave_map m = map_value (); + Octave_map::iterator i = m.begin (); + while (i != m.end ()) + { + octave_value val = map.contents (i); + + bool retval2 = add_hdf5_data (data_hid, val, m.key (i), "", false, + save_as_floats); + + if (! retval2) + break; + + i++; + } + + H5Gclose (data_hid); + + return true; +} + +bool +octave_class::load_hdf5 (hid_t loc_id, const char *name, + bool have_h5giterate_bug) +{ + bool retval = false; + + hdf5_callback_data dsub; + + herr_t retval2 = 0; + Octave_map m (dim_vector (1, 1)); + int current_item = 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); + + while (current_item < static_cast (num_obj) + && (retval2 = H5Giterate (loc_id, name, ¤t_item, + hdf5_read_next_data, &dsub)) > 0) +#else + while ((retval2 = H5Giterate (loc_id, name, ¤t_item, + hdf5_read_next_data, &dsub)) > 0) +#endif + { + octave_value t2 = dsub.tc; + + Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2); + + if (error_state) + { + error ("load: internal error loading class elements"); + return false; + } + + m.assign (dsub.name, tcell); + + if (have_h5giterate_bug) + current_item++; // H5Giterate returned the last index processed + } + + if (retval2 >= 0) + { + map = m; + retval = true; + } + + return retval; +} + +#endif + +#endif + +mxArray * +octave_class::as_mxArray (void) const +{ + gripe_wrong_type_arg ("octave_class::as_mxArray ()", type_name ()); + + return 0; +} + +bool +octave_class::in_class_method (void) const +{ + octave_function *fcn = octave_call_stack::current (); + + return (fcn + && (fcn->is_class_method () || fcn->is_class_constructor ()) + && fcn->dispatch_class () == class_name ()); +} + +DEFUN (class, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} class (@var{expr})\n\ +@deftypefnx {Built-in Function} {} class (@var{s}, @var{id})\n\ +\n\ +Return the class of the expression @var{expr}, as a string or\n\ +create a class object from the structure @var{s} with name @var{id}.\n\ +@end deftypefn") +{ + octave_value retval; + + int nargin = args.length (); + + if (nargin == 1) + retval = args(0).class_name (); + else if (nargin == 2) + { + Octave_map m = args(0).map_value (); + + if (! error_state) + { + std::string id = args(1).string_value (); + + if (! error_state) + { + octave_function *fcn = octave_call_stack::caller (); + + if (fcn && fcn->is_class_constructor ()) + retval = octave_value (new octave_class (m, id)); + else + error ("class: invalid call from outside class constructor"); + } + else + error ("class: expecting character string as second argument"); + } + else + error ("class: expecting structure as first argument"); + } + else + print_usage (); + + return retval; +} + + +DEFUN (isobject, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} isobject (@var{x})\n\ +Return true if @var{x} is a class object.\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length () == 1) + retval = args(0).is_object (); + else + print_usage (); + + return retval; +} + +DEFCMD (methods, args, nargout, + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} methods (@var{x})\n\ +@deftypefnx {Built-in Function} {} methods (\"classname\")\n\ +Return a cell array containing the names of the methods for the\n\ +object @var{x} or the named class.\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length () == 1) + { + octave_value arg = args(0); + + std::string class_name; + + if (arg.is_object ()) + class_name = arg.class_name (); + else if (arg.is_string ()) + class_name = arg.string_value (); + else + error ("methods: expecting object or class name as argument"); + + if (! error_state) + { + string_vector sv = load_path::methods (class_name); + + if (nargout == 0) + { + octave_stdout << "Methods for class " << class_name << ":\n\n"; + + sv.list_in_columns (octave_stdout); + + octave_stdout << std::endl; + } + else + retval = sv; + } + } + else + print_usage (); + + return retval; +} + +static bool +is_built_in_class (const std::string& cn) +{ + static std::set built_in_class_names; + + if (built_in_class_names.empty ()) + { + built_in_class_names.insert ("double"); + built_in_class_names.insert ("single"); + built_in_class_names.insert ("cell"); + built_in_class_names.insert ("struct"); + built_in_class_names.insert ("logical"); + built_in_class_names.insert ("char"); + built_in_class_names.insert ("function handle"); + built_in_class_names.insert ("int8"); + built_in_class_names.insert ("uint8"); + built_in_class_names.insert ("int16"); + built_in_class_names.insert ("uint16"); + built_in_class_names.insert ("int32"); + built_in_class_names.insert ("uint32"); + built_in_class_names.insert ("int64"); + built_in_class_names.insert ("uint64"); + } + + return built_in_class_names.find (cn) != built_in_class_names.end (); +} + +static void +set_class_relationship (const std::string& sup_class, + const std::string& inf_class) +{ + // FIXME + + warning ("class precedence not implemented"); +} + +DEFUN (superiorto, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} superiorto (@var{class_name})\n\ +When called from a class constructor, mark the object currently\n\ +constructed as having a higher precedence than @var{class_name}.\n\ +This function may only be called from a class constructor.\n\ +@end deftypefn") +{ + octave_value retval; + + octave_function *fcn = octave_call_stack::caller (); + + if (fcn && fcn->is_class_constructor ()) + { + if (args.length () == 1) + { + std::string class_name = args(0).string_value (); + + if (! error_state) + { + if (! is_built_in_class (class_name)) + { + std::string this_class_name = fcn->name (); + + set_class_relationship (this_class_name, class_name); + } + else + { + // User defined classes always have higher precedence + // than built-in classes. + } + } + else + error ("superiorto: expecting argument to be class name"); + } + else + print_usage (); + } + else + error ("superiorto: invalid call from outside class constructor"); + + return retval; +} + +DEFUN (inferiorto, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} inferiorto (@var{class_name})\n\ +When called from a class constructor, mark the object currently\n\ +constructed as having a lower precedence than @var{class_name}.\n\ +This function may only be called from a class constructor.\n\ +@end deftypefn") +{ + octave_value retval; + + octave_function *fcn = octave_call_stack::caller (); + + if (fcn && fcn->is_class_constructor ()) + { + if (args.length () == 1) + { + std::string class_name = args(0).string_value (); + + if (! error_state) + { + if (! is_built_in_class (class_name)) + { + std::string this_class_name = fcn->name (); + + set_class_relationship (class_name, this_class_name); + } + else + error ("inferiorto: cannot give user-defined class lower precedence than built-in class"); + } + else + error ("inferiorto: expecting argument to be class name"); + } + else + print_usage (); + } + else + error ("inferiorto: invalid call from outside class constructor"); + + return retval; +} + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/ diff -r e70789e0cd92 -r 5215422865e0 src/ov-class.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ov-class.h Fri Dec 28 22:32:23 2007 +0000 @@ -0,0 +1,173 @@ +/* + +Copyright (C) 2007 John W. Eaton + +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 2, 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, write to the Free +Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. + +*/ + +#if !defined (octave_class_h) +#define octave_class_h 1 + +#include + +#include +#include + +#include "mx-base.h" +#include "str-vec.h" + +#include "error.h" +#include "oct-alloc.h" +#include "oct-map.h" +#include "ov-base.h" +#include "ov-typeinfo.h" + +class octave_value_list; + +class tree_walker; + +// Data structures. + +class +octave_class : public octave_base_value +{ +public: + + octave_class (void) + : octave_base_value () { } + + octave_class (const Octave_map& m, const std::string& id) + : octave_base_value (), map (m), c_name (id) { } + + octave_class (const octave_class& s) + : octave_base_value (s), map (s.map), c_name (s.c_name) { } + + ~octave_class (void) { } + + octave_base_value *clone (void) const { return new octave_class (*this); } + octave_base_value *empty_clone (void) const { return new octave_class (); } + + Cell dotref (const octave_value_list& idx); + + octave_value subsref (const std::string&, + const std::list&) + { + panic_impossible (); + return octave_value_list (); + } + + octave_value_list subsref (const std::string& type, + const std::list& idx, + int nargout); + + static octave_value numeric_conv (const Cell& val, + const std::string& type); + + octave_value subsasgn (const std::string& type, + const std::list& idx, + const octave_value& rhs); + + dim_vector dims (void) const { return map.dims (); } + + size_t byte_size (void) const; + + // This is the number of elements in each field. The total number + // of elements is numel () * nfields (). + octave_idx_type numel (void) const + { + dim_vector dv = dims (); + return dv.numel (); + } + + octave_idx_type nfields (void) const { return map.nfields (); } + + octave_value reshape (const dim_vector& new_dims) const + { return map.reshape (new_dims); } + + octave_value resize (const dim_vector& dv, bool = false) const + { Octave_map tmap = map; tmap.resize (dv); return tmap; } + + bool is_defined (void) const { return true; } + + bool is_map (void) const { return false; } + + bool is_object (void) const { return true; } + + Octave_map map_value (void) const; + + string_vector map_keys (void) const; + + void print (std::ostream& os, bool pr_as_read_syntax = false) const; + + void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; + + bool print_name_tag (std::ostream& os, const std::string& name) const; + + 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 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 + + mxArray *as_mxArray (void) const; + +private: + + Octave_map map; + + DECLARE_OCTAVE_ALLOCATOR + +public: + int type_id (void) const { return t_id; } + std::string type_name (void) const { return t_name; } + std::string class_name (void) const { return c_name; } + + static int static_type_id (void) { return t_id; } + static std::string static_type_name (void) { return t_name; } + static std::string static_class_name (void) { return ""; } + static void register_type (void); + +private: + static int t_id; + + static const std::string t_name; + std::string c_name; + + bool in_class_method (void) const; +}; + +#endif + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/