GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
op-class.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2007-2024 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 //! @file op-class.cc
27 //! Unary and binary operators for classdef and old style classes.
28 
29 #if defined (HAVE_CONFIG_H)
30 # include "config.h"
31 #endif
32 
33 #include "oct-time.h"
34 
35 #include "errwarn.h"
36 #include "interpreter-private.h"
37 #include "interpreter.h"
38 #include "load-path.h"
39 #include "ovl.h"
40 #include "ov.h"
41 #include "ov-class.h"
42 #include "ov-typeinfo.h"
43 #include "ops.h"
44 #include "symtab.h"
45 
47 
48 //! Default unary class operator.
49 //!
50 //! @param a operand
51 //! @param opname operator name
52 
53 static octave_value
54 oct_unop_default (const octave_value& a, const std::string& opname)
55 {
56  std::string class_name = a.class_name ();
57 
58  octave::interpreter& interp = octave::__get_interpreter__ ();
59 
60  octave::symbol_table& symtab = interp.get_symbol_table ();
61 
62  octave_value meth = symtab.find_method (opname, class_name);
63 
64  if (meth.is_defined ())
65  {
66  // Call overloaded unary class operator.
68  = interp.feval (meth.function_value (), ovl (a), 1);
69 
70  // Return first element if present.
71  if (tmp.length () > 0)
72  return tmp(0);
73 
74  return octave_value ();
75  }
76 
77  // Matlab compatibility: If (conjugate) transpose is not overloaded and
78  // the number of dimensions is maximal two, just transpose the array of
79  // that class.
80 
81  if ((opname == "transpose") || (opname == "ctranspose"))
82  {
83  if (a.ndims () > 2)
84  error ("%s not defined for N-D objects of %s class", opname.c_str (),
85  class_name.c_str ());
86 
87  if (a.is_classdef_object ())
88  {
89  // FIXME: Default transposition for classdef arrays.
90 
91  error ("%s method not defined for %s class", opname.c_str (),
92  class_name.c_str ());
93  }
94  else
95  {
97 
98  return octave_value (v.map_value ().transpose (),
99  v.class_name (),
100  v.parent_class_name_list ());
101  }
102  }
103  else
104  error ("%s method not defined for %s class", opname.c_str (),
105  class_name.c_str ());
106 }
107 
108 //! Helper macro to define unary class operators.
109 
110 #define DEF_CLASS_UNOP(opname) \
111  static octave_value \
112  oct_unop_ ## opname (const octave_value& a) \
113  { \
114  return oct_unop_default (a, #opname); \
115  }
116 
117 DEF_CLASS_UNOP (not) // !a or ~a
118 DEF_CLASS_UNOP (uplus) // +a
119 DEF_CLASS_UNOP (uminus) // -a
120 DEF_CLASS_UNOP (transpose) // a.'
121 DEF_CLASS_UNOP (ctranspose) // a'
122 #undef DEF_CLASS_UNOP
123 
124 //! Default binary class operator.
125 //!
126 //! @param a1 first operand
127 //! @param a2 second operand
128 //! @param opname operator name
129 //!
130 //! The operator precedence is as follows:
131 //!
132 //! 1. If exactly one of the operands is a user defined class object, then
133 //! the class method of that operand is invoked.
134 //!
135 //! 2. If both operands are user defined class objects, then
136 //! 2.1 The superior class method is invoked.
137 //! 2.2 The leftmost class method is invoked if both classes are the same
138 //! or their precedence is not defined by superiorto/inferiorto.
139 
140 static octave_value
141 oct_binop_default (const octave_value& a1, const octave_value& a2,
142  const std::string& opname)
143 {
144  octave::interpreter& interp = octave::__get_interpreter__ ();
145 
146  octave::symbol_table& symtab = interp.get_symbol_table ();
147 
148  // Dispatch to first (leftmost) operand by default.
149  std::string dispatch_type = a1.class_name ();
150 
151  // Determine, if second operand takes precedence (see rules above).
152  if (! a1.isobject ()
153  || (a1.isobject () && a2.isobject ()
154  && symtab.is_superiorto (a2.class_name (), dispatch_type)))
155  dispatch_type = a2.class_name ();
156 
157  octave_value meth = symtab.find_method (opname, dispatch_type);
158 
159  if (meth.is_undefined ())
160  error ("%s method not defined for %s class", opname.c_str (),
161  dispatch_type.c_str ());
162 
164  = interp.feval (meth.function_value (), ovl (a1, a2), 1);
165 
166  if (tmp.length () > 0)
167  return tmp(0);
168 
169  return octave_value ();
170 }
171 
172 //! Helper macro to define binary class operators.
173 
174 #define DEF_CLASS_BINOP(opname) \
175  static octave_value \
176  oct_binop_ ## opname (const octave_value& a1, const octave_value& a2) \
177  { \
178  return oct_binop_default (a1, a2, #opname); \
179  }
180 
181 DEF_CLASS_BINOP (plus) // a1 + a2
182 DEF_CLASS_BINOP (minus) // a1 - a2
183 DEF_CLASS_BINOP (mtimes) // a1 * a2
184 DEF_CLASS_BINOP (mrdivide) // a1 / a2
185 DEF_CLASS_BINOP (mpower) // a1 ^ a2
186 DEF_CLASS_BINOP (mldivide) // a1 \ a2
187 DEF_CLASS_BINOP (lt) // a1 < a2
188 DEF_CLASS_BINOP (le) // a1 <= a2
189 DEF_CLASS_BINOP (eq) // a1 <= a2
190 DEF_CLASS_BINOP (ge) // a1 >= a2
191 DEF_CLASS_BINOP (gt) // a1 > a2
192 DEF_CLASS_BINOP (ne) // a1 ~= a2 or a1 != a2
193 DEF_CLASS_BINOP (times) // a1 .* a2
194 DEF_CLASS_BINOP (rdivide) // a1 ./ a2
195 DEF_CLASS_BINOP (power) // a1 .^ a2
196 DEF_CLASS_BINOP (ldivide) // a1 .\ a2
197 DEF_CLASS_BINOP (and) // a1 & a2
198 DEF_CLASS_BINOP (or) // a1 | a2
199 #undef DEF_CLASS_BINOP
200 
201 void
202 install_class_ops (octave::type_info& ti)
203 {
204  ti.install_unary_class_op (octave_value::op_not, oct_unop_not);
205  ti.install_unary_class_op (octave_value::op_uplus, oct_unop_uplus);
206  ti.install_unary_class_op (octave_value::op_uminus, oct_unop_uminus);
207  ti.install_unary_class_op (octave_value::op_transpose, oct_unop_transpose);
208  ti.install_unary_class_op (octave_value::op_hermitian, oct_unop_ctranspose);
209 
210  ti.install_binary_class_op (octave_value::op_add, oct_binop_plus);
211  ti.install_binary_class_op (octave_value::op_sub, oct_binop_minus);
212  ti.install_binary_class_op (octave_value::op_mul, oct_binop_mtimes);
213  ti.install_binary_class_op (octave_value::op_div, oct_binop_mrdivide);
214  ti.install_binary_class_op (octave_value::op_pow, oct_binop_mpower);
215  ti.install_binary_class_op (octave_value::op_ldiv, oct_binop_mldivide);
216  ti.install_binary_class_op (octave_value::op_lt, oct_binop_lt);
217  ti.install_binary_class_op (octave_value::op_le, oct_binop_le);
218  ti.install_binary_class_op (octave_value::op_eq, oct_binop_eq);
219  ti.install_binary_class_op (octave_value::op_ge, oct_binop_ge);
220  ti.install_binary_class_op (octave_value::op_gt, oct_binop_gt);
221  ti.install_binary_class_op (octave_value::op_ne, oct_binop_ne);
222  ti.install_binary_class_op (octave_value::op_el_mul, oct_binop_times);
223  ti.install_binary_class_op (octave_value::op_el_div, oct_binop_rdivide);
224  ti.install_binary_class_op (octave_value::op_el_pow, oct_binop_power);
225  ti.install_binary_class_op (octave_value::op_el_ldiv, oct_binop_ldivide);
226  ti.install_binary_class_op (octave_value::op_el_and, oct_binop_and);
227  ti.install_binary_class_op (octave_value::op_el_or, oct_binop_or);
228 }
229 
230 OCTAVE_END_NAMESPACE(octave)
virtual bool isobject() const
Definition: ov-base.h:451
virtual std::string class_name() const
Definition: ov-base.h:954
octave_idx_type length() const
Definition: ovl.h:113
bool is_classdef_object() const
Definition: ov.h:655
bool is_undefined() const
Definition: ov.h:595
std::string class_name() const
Definition: ov.h:1347
@ op_hermitian
Definition: ov.h:84
@ op_uminus
Definition: ov.h:82
@ op_not
Definition: ov.h:80
@ op_transpose
Definition: ov.h:83
@ op_uplus
Definition: ov.h:81
int ndims() const
Definition: ov.h:551
bool is_defined() const
Definition: ov.h:592
const octave_base_value & get_rep() const
Definition: ov.h:1359
octave_function * function_value(bool silent=false) const
@ op_ldiv
Definition: ov.h:98
@ op_ne
Definition: ov.h:104
@ op_el_or
Definition: ov.h:110
@ op_el_ldiv
Definition: ov.h:108
@ op_pow
Definition: ov.h:97
@ op_ge
Definition: ov.h:102
@ op_div
Definition: ov.h:96
@ op_el_pow
Definition: ov.h:107
@ op_mul
Definition: ov.h:95
@ op_add
Definition: ov.h:93
@ op_sub
Definition: ov.h:94
@ op_el_mul
Definition: ov.h:105
@ op_le
Definition: ov.h:100
@ op_lt
Definition: ov.h:99
@ op_gt
Definition: ov.h:103
@ op_eq
Definition: ov.h:101
@ op_el_and
Definition: ov.h:109
@ op_el_div
Definition: ov.h:106
bool isobject() const
Definition: ov.h:664
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void() error(const char *fmt,...)
Definition: error.cc:988
interpreter & __get_interpreter__()
#define DEF_CLASS_BINOP(opname)
Helper macro to define binary class operators.
Definition: op-class.cc:174
void install_class_ops(octave::type_info &ti)
Definition: op-class.cc:202
#define DEF_CLASS_UNOP(opname)
Helper macro to define unary class operators.
Definition: op-class.cc:110
const octave_base_value & a2
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
#define OCTAVE_CAST_BASE_VALUE(T, T_VAL, BASE_VAL)
Definition: ops.h:52
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:219