GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
op-class.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2007-2025 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
53static octave_value
54oct_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
117DEF_CLASS_UNOP (not) // !a or ~a
118DEF_CLASS_UNOP (uplus) // +a
119DEF_CLASS_UNOP (uminus) // -a
120DEF_CLASS_UNOP (transpose) // a.'
121DEF_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
140static octave_value
141oct_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
181DEF_CLASS_BINOP (plus) // a1 + a2
182DEF_CLASS_BINOP (minus) // a1 - a2
183DEF_CLASS_BINOP (mtimes) // a1 * a2
184DEF_CLASS_BINOP (mrdivide) // a1 / a2
185DEF_CLASS_BINOP (mpower) // a1 ^ a2
186DEF_CLASS_BINOP (mldivide) // a1 \ a2
187DEF_CLASS_BINOP (lt) // a1 < a2
188DEF_CLASS_BINOP (le) // a1 <= a2
189DEF_CLASS_BINOP (eq) // a1 <= a2
190DEF_CLASS_BINOP (ge) // a1 >= a2
191DEF_CLASS_BINOP (gt) // a1 > a2
192DEF_CLASS_BINOP (ne) // a1 ~= a2 or a1 != a2
193DEF_CLASS_BINOP (times) // a1 .* a2
194DEF_CLASS_BINOP (rdivide) // a1 ./ a2
195DEF_CLASS_BINOP (power) // a1 .^ a2
196DEF_CLASS_BINOP (ldivide) // a1 .\ a2
197DEF_CLASS_BINOP (and) // a1 & a2
198DEF_CLASS_BINOP (or) // a1 | a2
199#undef DEF_CLASS_BINOP
200
201void
202install_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
230OCTAVE_END_NAMESPACE(octave)
virtual bool isobject() const
Definition ov-base.h:463
virtual std::string class_name() const
Definition ov-base.h:977
octave_idx_type length() const
Definition ovl.h:111
bool is_classdef_object() const
Definition ov.h:655
const octave_base_value & get_rep() const
Definition ov.h:1374
bool is_undefined() const
Definition ov.h:595
std::string class_name() const
Definition ov.h:1362
octave_function * function_value(bool silent=false) const
@ 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
@ 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:1003
#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
#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:217