Mercurial > octave
changeset 27098:5fa8d1459b35
* libinterp/operators/op-class.cc: Overhaul file and document code.
No functional changes, Doxygen and comments added.
Refactor large portions of the macros DEF_CLASS_UNOP and DEF_CLASS_BINOP to
proper c++ functions "oct_unop_default" and "oct_binop_default". The macro
DEF_CLASS_UNOP_TRANS is no longer necessary.
Expanded and removed the macros INSTALL_CLASS_UNOP_TI and INSTALL_CLASS_BINOP_TI
to improve readability.
author | Kai T. Ohlhus <k.ohlhus@gmail.com> |
---|---|
date | Tue, 21 May 2019 10:00:52 +0200 |
parents | bdd2964964cc |
children | 2cd31365c84a |
files | libinterp/operators/op-class.cc |
diffstat | 1 files changed, 166 insertions(+), 170 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/operators/op-class.cc Mon May 20 09:46:30 2019 +0200 +++ b/libinterp/operators/op-class.cc Tue May 21 10:00:52 2019 +0200 @@ -20,6 +20,9 @@ */ +//! @file op-class.cc +//! Unary and binary operators for classdef and old style classes. + #if defined (HAVE_CONFIG_H) # include "config.h" #endif @@ -37,189 +40,182 @@ #include "symtab.h" #include "parse.h" -// class ops. +//! Default unary class operator. +//! +//! @param a operand +//! @param opname operator name + +static octave_value +oct_unop_default (const octave_value& a, const std::string& opname) +{ + std::string class_name = a.class_name (); + + octave_value meth + = octave::__get_symbol_table__ ("oct_unop_" + opname) + .find_method (opname, class_name); + + if (meth.is_defined ()) + { + // Call overloaded unary class operator. + octave_value_list tmp = octave::feval (meth.function_value (), + ovl (a), 1); + + // Return first element if present. + if (tmp.length () > 0) + return tmp(0); + + return octave_value (); + } + + // Matlab compatibility: If (conjugate) transpose is not overloaded and + // the number of dimensions is maximal two, just transpose the array of + // that class. -#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::symbol_table& symtab \ - = octave::__get_symbol_table__ ("oct_unop_" #name); \ - \ - octave_value meth = symtab.find_method (#name, class_name); \ - \ - if (meth.is_undefined ()) \ - error ("%s method not defined for %s class", #name, \ - class_name.c_str ()); \ - \ - octave_value_list args; \ - \ - args(0) = a; \ - \ - octave_value_list tmp = octave::feval (meth.function_value (), args, 1); \ - \ - if (tmp.length () > 0) \ - retval = tmp(0); \ - \ - return retval; \ + if ((opname == "transpose") || (opname == "ctranspose")) + { + if (a.ndims () > 2) + error ("%s not defined for N-D objects of %s class", opname.c_str (), + class_name.c_str ()); + + if (a.is_classdef_object ()) + { + // FIXME: Default transposition for classdef arrays. + + error ("%s method not defined for %s class", opname.c_str (), + class_name.c_str ()); + } + else + { + const octave_class& v + = dynamic_cast<const octave_class&> (a.get_rep ()); + + return octave_value (v.map_value ().transpose (), + v.class_name (), + v.parent_class_name_list ()); + } + } + else + error ("%s method not defined for %s class", opname.c_str (), + class_name.c_str ()); +} + +//! Helper macro to define unary class operators. + +#define DEF_CLASS_UNOP(opname) \ + static octave_value \ + oct_unop_ ## opname (const octave_value& a) \ + { \ + return oct_unop_default (a, #opname); \ } -DEF_CLASS_UNOP (not) -DEF_CLASS_UNOP (uplus) -DEF_CLASS_UNOP (uminus) +DEF_CLASS_UNOP (not) // !a or ~a +DEF_CLASS_UNOP (uplus) // +a +DEF_CLASS_UNOP (uminus) // -a +DEF_CLASS_UNOP (transpose) // a.' +DEF_CLASS_UNOP (ctranspose) // a' +#undef DEF_CLASS_UNOP + +//! Default binary class operator. +//! +//! @param a1 first operand +//! @param a2 second operand +//! @param opname operator name +//! +//! The operator precedence is as follows: +//! +//! 1. If exactly one of the operands is a user defined class object, then +//! the class method of that operand is invoked. +//! +//! 2. If both operands are user defined class objects, then +//! 2.1 The superior class method is invoked. +//! 2.2 The leftmost class method is invoked if both classes are the same +//! or their precedence is not defined by superiorto/inferiorto. + +static octave_value +oct_binop_default (const octave_value& a1, const octave_value& a2, + const std::string& opname) +{ + octave::symbol_table& symtab + = octave::__get_symbol_table__ ("oct_binop_" + opname); -// In case of (conjugate) transpose first check for overloaded class method. -// If not overloaded, just transpose the underlying map_value, if the number -// of dimensions is maximal two. Matlab compatibility. + // Dispatch to first (leftmost) operand by default. + std::string dispatch_type = a1.class_name (); + + // Determine, if second operand takes precedence (see rules above). + if (! a1.isobject () + || (a1.isobject () && a2.isobject () + && symtab.is_superiorto (a2.class_name (), dispatch_type))) + dispatch_type = a2.class_name (); + + octave_value meth = symtab.find_method (opname, dispatch_type); + + if (meth.is_undefined ()) + error ("%s method not defined for %s class", opname.c_str (), + dispatch_type.c_str ()); -// FIXME: Default transposition for classdef arrays. + octave_value_list tmp = octave::feval (meth.function_value (), + ovl (a1, a2), 1); + + if (tmp.length () > 0) + return tmp(0); -#define DEF_CLASS_UNOP_TRANS(name) \ + return octave_value (); +} + +//! Helper macro to define binary class operators. + +#define DEF_CLASS_BINOP(opname) \ static octave_value \ - oct_unop_ ## name (const octave_value& a) \ + oct_binop_ ## opname (const octave_value& a1, const octave_value& a2) \ { \ - octave_value retval; \ - \ - std::string class_name = a.class_name (); \ - \ - octave::symbol_table& symtab \ - = octave::__get_symbol_table__ ("oct_unop_" #name); \ - \ - octave_value meth = symtab.find_method (#name, class_name); \ - \ - if (meth.is_undefined ()) \ - { \ - if (a.ndims () > 2) \ - error ("#name not defined for N-D objects"); \ - \ - if (! a.is_classdef_object ()) \ - { \ - const octave_class& v \ - = dynamic_cast<const octave_class&> (a.get_rep ()); \ - \ - return octave_value (v.map_value ().transpose (), \ - v.class_name (), \ - v.parent_class_name_list ()); \ - } \ - else \ - error ("%s method not defined for %s class", #name, \ - class_name.c_str ()); \ - } \ - \ - octave_value_list args; \ - \ - args(0) = a; \ - \ - octave_value_list tmp = octave::feval (meth.function_value (), args, 1); \ - \ - if (tmp.length () > 0) \ - retval = tmp(0); \ - \ - return retval; \ + return oct_binop_default (a1, a2, #opname); \ } -DEF_CLASS_UNOP_TRANS (transpose) -DEF_CLASS_UNOP_TRANS (ctranspose) - -// The precedence of the oct_binop_*-functions is as follows: -// -// 1. If exactly one of the arguments is a user defined class object, then -// the function of that operand's class is invoked. -// -// 2. If both arguments are user defined class objects, then -// 2.1 The superior class function is invoked. -// 2.2 The leftmost class function is invoked if both classes are the same -// or their precedence is not defined by superiorto/inferiorto. - -#define DEF_CLASS_BINOP(name) \ - static octave_value \ - oct_binop_ ## name (const octave_value& a1, const octave_value& a2) \ - { \ - octave_value retval; \ - \ - octave::symbol_table& symtab \ - = octave::__get_symbol_table__ ("oct_binop_" #name); \ - \ - std::string dispatch_type = a1.class_name (); \ - \ - if (! a1.isobject () \ - || (a1.isobject () && a2.isobject () \ - && symtab.is_superiorto (a2.class_name (), dispatch_type))) \ - dispatch_type = a2.class_name (); \ - \ - octave_value meth = symtab.find_method (#name, dispatch_type); \ - \ - if (meth.is_undefined ()) \ - error ("%s method not defined for %s class", #name, \ - dispatch_type.c_str ()); \ - \ - octave_value_list args; \ - \ - args(1) = a2; \ - args(0) = a1; \ - \ - octave_value_list tmp = octave::feval (meth.function_value (), args, 1); \ - \ - if (tmp.length () > 0) \ - retval = tmp(0); \ - \ - 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_TI(ti, op, f) \ - ti.install_unary_class_op (octave_value::op, oct_unop_ ## f) - -#define INSTALL_CLASS_BINOP_TI(ti, op, f) \ - ti.install_binary_class_op (octave_value::op, oct_binop_ ## f) +DEF_CLASS_BINOP (plus) // a1 + a2 +DEF_CLASS_BINOP (minus) // a1 - a2 +DEF_CLASS_BINOP (mtimes) // a1 * a2 +DEF_CLASS_BINOP (mrdivide) // a1 / a2 +DEF_CLASS_BINOP (mpower) // a1 ^ a2 +DEF_CLASS_BINOP (mldivide) // a1 \ a2 +DEF_CLASS_BINOP (lt) // a1 < a2 +DEF_CLASS_BINOP (le) // a1 <= a2 +DEF_CLASS_BINOP (eq) // a1 <= a2 +DEF_CLASS_BINOP (ge) // a1 >= a2 +DEF_CLASS_BINOP (gt) // a1 > a2 +DEF_CLASS_BINOP (ne) // a1 ~= a2 or a1 != a2 +DEF_CLASS_BINOP (times) // a1 .* a2 +DEF_CLASS_BINOP (rdivide) // a1 ./ a2 +DEF_CLASS_BINOP (power) // a1 .^ a2 +DEF_CLASS_BINOP (ldivide) // a1 .\ a2 +DEF_CLASS_BINOP (and) // a1 & a2 +DEF_CLASS_BINOP (or) // a1 | a2 +#undef DEF_CLASS_BINOP void install_class_ops (octave::type_info& ti) { - INSTALL_CLASS_UNOP_TI (ti, op_not, not); - INSTALL_CLASS_UNOP_TI (ti, op_uplus, uplus); - INSTALL_CLASS_UNOP_TI (ti, op_uminus, uminus); - INSTALL_CLASS_UNOP_TI (ti, op_transpose, transpose); - INSTALL_CLASS_UNOP_TI (ti, op_hermitian, ctranspose); + ti.install_unary_class_op (octave_value::op_not, oct_unop_not); + ti.install_unary_class_op (octave_value::op_uplus, oct_unop_uplus); + ti.install_unary_class_op (octave_value::op_uminus, oct_unop_uminus); + ti.install_unary_class_op (octave_value::op_transpose, oct_unop_transpose); + ti.install_unary_class_op (octave_value::op_hermitian, oct_unop_ctranspose); - INSTALL_CLASS_BINOP_TI (ti, op_add, plus); - INSTALL_CLASS_BINOP_TI (ti, op_sub, minus); - INSTALL_CLASS_BINOP_TI (ti, op_mul, mtimes); - INSTALL_CLASS_BINOP_TI (ti, op_div, mrdivide); - INSTALL_CLASS_BINOP_TI (ti, op_pow, mpower); - INSTALL_CLASS_BINOP_TI (ti, op_ldiv, mldivide); - INSTALL_CLASS_BINOP_TI (ti, op_lt, lt); - INSTALL_CLASS_BINOP_TI (ti, op_le, le); - INSTALL_CLASS_BINOP_TI (ti, op_eq, eq); - INSTALL_CLASS_BINOP_TI (ti, op_ge, ge); - INSTALL_CLASS_BINOP_TI (ti, op_gt, gt); - INSTALL_CLASS_BINOP_TI (ti, op_ne, ne); - INSTALL_CLASS_BINOP_TI (ti, op_el_mul, times); - INSTALL_CLASS_BINOP_TI (ti, op_el_div, rdivide); - INSTALL_CLASS_BINOP_TI (ti, op_el_pow, power); - INSTALL_CLASS_BINOP_TI (ti, op_el_ldiv, ldivide); - INSTALL_CLASS_BINOP_TI (ti, op_el_and, and); - INSTALL_CLASS_BINOP_TI (ti, op_el_or, or); + ti.install_binary_class_op (octave_value::op_add, oct_binop_plus); + ti.install_binary_class_op (octave_value::op_sub, oct_binop_minus); + ti.install_binary_class_op (octave_value::op_mul, oct_binop_mtimes); + ti.install_binary_class_op (octave_value::op_div, oct_binop_mrdivide); + ti.install_binary_class_op (octave_value::op_pow, oct_binop_mpower); + ti.install_binary_class_op (octave_value::op_ldiv, oct_binop_mldivide); + ti.install_binary_class_op (octave_value::op_lt, oct_binop_lt); + ti.install_binary_class_op (octave_value::op_le, oct_binop_le); + ti.install_binary_class_op (octave_value::op_eq, oct_binop_eq); + ti.install_binary_class_op (octave_value::op_ge, oct_binop_ge); + ti.install_binary_class_op (octave_value::op_gt, oct_binop_gt); + ti.install_binary_class_op (octave_value::op_ne, oct_binop_ne); + ti.install_binary_class_op (octave_value::op_el_mul, oct_binop_times); + ti.install_binary_class_op (octave_value::op_el_div, oct_binop_rdivide); + ti.install_binary_class_op (octave_value::op_el_pow, oct_binop_power); + ti.install_binary_class_op (octave_value::op_el_ldiv, oct_binop_ldivide); + ti.install_binary_class_op (octave_value::op_el_and, oct_binop_and); + ti.install_binary_class_op (octave_value::op_el_or, oct_binop_or); }