GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
syminfo.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2018-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 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <iomanip>
31 #include <list>
32 #include <ostream>
33 #include <sstream>
34 
35 #include "Cell.h"
36 #include "error.h"
38 #include "ov.h"
39 #include "oct-map.h"
40 #include "pager.h"
41 #include "syminfo.h"
42 
44 
45 void
46 symbol_info::display_line (std::ostream& os,
47  const std::list<whos_parameter>& params) const
48 {
49  std::string dims_str = m_value.get_dims_str ();
50 
51  auto i = params.begin ();
52 
53  preserve_stream_state stream_state (os);
54 
55  while (i != params.end ())
56  {
57  whos_parameter param = *i;
58 
59  if (param.command != '\0')
60  {
61  // Do the actual printing.
62 
63  switch (param.modifier)
64  {
65  case 'l':
66  os << std::setiosflags (std::ios::left)
67  << std::setw (param.parameter_length);
68  break;
69 
70  case 'r':
71  os << std::setiosflags (std::ios::right)
72  << std::setw (param.parameter_length);
73  break;
74 
75  case 'c':
76  if (param.command == 's')
77  {
78  int front = param.first_parameter_length
79  - dims_str.find ('x');
80  int back = param.parameter_length
81  - dims_str.length ()
82  - front;
83  front = (front > 0) ? front : 0;
84  back = (back > 0) ? back : 0;
85 
86  os << std::setiosflags (std::ios::left)
87  << std::setw (front)
88  << ""
89  << std::resetiosflags (std::ios::left)
90  << dims_str
91  << std::setiosflags (std::ios::left)
92  << std::setw (back)
93  << ""
94  << std::resetiosflags (std::ios::left);
95  }
96  else
97  {
98  os << std::setiosflags (std::ios::left)
99  << std::setw (param.parameter_length);
100  }
101  break;
102 
103  default:
104  error ("whos_line_format: modifier '%c' unknown",
105  param.modifier);
106  }
107 
108  switch (param.command)
109  {
110  case 'a':
111  {
112  char tmp[6];
113 
114  tmp[0] = (m_is_complex ? 'c' : ' ');
115  tmp[1] = (m_is_sparse ? 's' : ' ');
116  tmp[2] = (m_is_formal ? 'f' : ' ');
117  tmp[3] = (m_is_global ? 'g' : ' ');
118  tmp[4] = (m_is_persistent ? 'p' : ' ');
119  tmp[5] = 0;
120 
121  os << tmp;
122  }
123  break;
124 
125  case 'b':
126  os << m_value.byte_size ();
127  break;
128 
129  case 'c':
130  os << m_value.class_name ();
131  break;
132 
133  case 'e':
134  os << m_value.numel ();
135  break;
136 
137  case 'n':
138  os << m_name;
139  break;
140 
141  case 's':
142  if (param.modifier != 'c')
143  os << dims_str;
144  break;
145 
146  case 't':
147  os << m_value.type_name ();
148  break;
149 
150  default:
151  error ("whos_line_format: command '%c' unknown",
152  param.command);
153  }
154 
155  os << std::resetiosflags (std::ios::left)
156  << std::resetiosflags (std::ios::right);
157  i++;
158  }
159  else
160  {
161  os << param.text;
162  i++;
163  }
164  }
165 }
166 
167 // FIXME: should we be using std::map<symbol_info> instead of a list?
168 
170 symbol_info_list::varval (const std::string& name) const
171 {
172  for (const auto& syminfo : m_lst)
173  {
174  if (name == syminfo.name ())
175  return syminfo.value ();
176  }
177 
178  return octave_value ();
179 }
180 
181 std::list<std::string>
183 {
184  std::list<std::string> retval;
185 
186  for (const auto& syminfo : m_lst)
187  retval.push_back (syminfo.name ());
188 
189  return retval;
190 }
191 
193 symbol_info_list::map_value (const std::string& caller_function_name,
194  int nesting_level) const
195 {
196  std::size_t len = m_lst.size ();
197 
198  Cell name_info (len, 1);
199  Cell size_info (len, 1);
200  Cell bytes_info (len, 1);
201  Cell class_info (len, 1);
202  Cell global_info (len, 1);
203  Cell sparse_info (len, 1);
204  Cell complex_info (len, 1);
205  Cell nesting_info (len, 1);
206  Cell persistent_info (len, 1);
207 
208  std::size_t j = 0;
209 
210  for (const auto& syminfo : m_lst)
211  {
213 
214  ni.assign ("function", caller_function_name);
215  ni.assign ("level", nesting_level);
216 
217  name_info(j) = syminfo.name ();
218  global_info(j) = syminfo.is_global ();
219  persistent_info(j) = syminfo.is_persistent ();
220 
221  octave_value val = syminfo.value ();
222 
223  size_info(j) = val.size ();
224  bytes_info(j) = val.byte_size ();
225  class_info(j) = val.class_name ();
226  sparse_info(j) = val.issparse ();
227  complex_info(j) = val.iscomplex ();
228  nesting_info(j) = ni;
229 
230  j++;
231  }
232 
233  octave_map info;
234 
235  info.assign ("name", name_info);
236  info.assign ("size", size_info);
237  info.assign ("bytes", bytes_info);
238  info.assign ("class", class_info);
239  info.assign ("global", global_info);
240  info.assign ("sparse", sparse_info);
241  info.assign ("complex", complex_info);
242  info.assign ("nesting", nesting_info);
243  info.assign ("persistent", persistent_info);
244 
245  return info;
246 }
247 
248 void
250  const std::list<whos_parameter> params) const
251 {
252  std::ostringstream param_buf;
253 
254  preserve_stream_state stream_state (os);
255 
256  for (const auto& param : params)
257  {
258  if (param.command != '\0')
259  {
260  // Do the actual printing
261  switch (param.modifier)
262  {
263  case 'l':
264  os << std::setiosflags (std::ios::left)
265  << std::setw (param.parameter_length);
266  param_buf << std::setiosflags (std::ios::left)
267  << std::setw (param.parameter_length);
268  break;
269 
270  case 'r':
271  os << std::setiosflags (std::ios::right)
272  << std::setw (param.parameter_length);
273  param_buf << std::setiosflags (std::ios::right)
274  << std::setw (param.parameter_length);
275  break;
276 
277  case 'c':
278  if (param.command != 's')
279  {
280  os << std::setiosflags (std::ios::left)
281  << std::setw (param.parameter_length);
282  param_buf << std::setiosflags (std::ios::left)
283  << std::setw (param.parameter_length);
284  }
285  break;
286 
287  default:
288  os << std::setiosflags (std::ios::left)
289  << std::setw (param.parameter_length);
290  param_buf << std::setiosflags (std::ios::left)
291  << std::setw (param.parameter_length);
292  }
293 
294  if (param.command == 's' && param.modifier == 'c')
295  {
296  int a = param.first_parameter_length - param.balance;
297  a = (a < 0 ? 0 : a);
298  int b = param.parameter_length - a - param.text.length ();
299  b = (b < 0 ? 0 : b);
300  os << std::setiosflags (std::ios::left) << std::setw (a)
301  << "" << std::resetiosflags (std::ios::left) << param.text
302  << std::setiosflags (std::ios::left)
303  << std::setw (b) << ""
304  << std::resetiosflags (std::ios::left);
305  param_buf << std::setiosflags (std::ios::left)
306  << std::setw (a)
307  << "" << std::resetiosflags (std::ios::left)
308  << param.line
309  << std::setiosflags (std::ios::left)
310  << std::setw (b) << ""
311  << std::resetiosflags (std::ios::left);
312  }
313  else
314  {
315  os << param.text;
316  param_buf << param.line;
317  }
318  os << std::resetiosflags (std::ios::left)
319  << std::resetiosflags (std::ios::right);
320  param_buf << std::resetiosflags (std::ios::left)
321  << std::resetiosflags (std::ios::right);
322  }
323  else
324  {
325  os << param.text;
326  param_buf << param.line;
327  }
328  }
329 
330  os << param_buf.str ();
331 }
332 
333 void
334 symbol_info_list::display (std::ostream& os,
335  const std::string& format) const
336 {
337  if (! m_lst.empty ())
338  {
339  std::size_t bytes = 0;
340  std::size_t elements = 0;
341 
342  std::list<whos_parameter> params = parse_whos_line_format (format);
343 
344  print_descriptor (os, params);
345 
346  octave_stdout << "\n";
347 
348  for (const auto& syminfo : m_lst)
349  {
350  syminfo.display_line (os, params);
351 
352  octave_value val = syminfo.value ();
353 
354  elements += val.numel ();
355  bytes += val.byte_size ();
356  }
357 
358  os << "\nTotal is " << elements
359  << (elements == 1 ? " element" : " elements")
360  << " using " << bytes << (bytes == 1 ? " byte" : " bytes")
361  << "\n";
362  }
363 }
364 
365 std::list<whos_parameter>
367 {
368  int idx;
369  std::size_t format_len = format.length ();
370  char garbage;
371  std::list<whos_parameter> params;
372 
373  std::size_t bytes1;
374  int elements1;
375 
376  std::string param_string = "abcenst";
377  Array<int> param_length (dim_vector (param_string.length (), 1));
378  Array<std::string> param_names (dim_vector (param_string.length (), 1));
379  std::size_t pos_a, pos_b, pos_c, pos_e, pos_n, pos_s, pos_t;
380 
381  pos_a = param_string.find ('a'); // Attributes
382  pos_b = param_string.find ('b'); // Bytes
383  pos_c = param_string.find ('c'); // Class
384  pos_e = param_string.find ('e'); // Elements
385  pos_n = param_string.find ('n'); // Name
386  pos_s = param_string.find ('s'); // Size
387  pos_t = param_string.find ('t'); // Type
388 
389  param_names(pos_a) = "Attr";
390  param_names(pos_b) = "Bytes";
391  param_names(pos_c) = "Class";
392  param_names(pos_e) = "Elements";
393  param_names(pos_n) = "Name";
394  param_names(pos_s) = "Size";
395  param_names(pos_t) = "Type";
396 
397  for (std::size_t i = 0; i < param_string.length (); i++)
398  param_length(i) = param_names(i).length ();
399 
400  // The attribute column needs size 6.
401  param_length(pos_a) = 6;
402 
403  // Calculating necessary spacing for name column,
404  // bytes column, elements column and class column
405 
406  for (const auto& syminfo : m_lst)
407  {
408  std::stringstream ss1, ss2;
409  std::string str;
410 
411  str = syminfo.name ();
412  param_length(pos_n) = ((str.length ()
413  > static_cast<std::size_t> (param_length(pos_n)))
414  ? str.length () : param_length(pos_n));
415 
416  octave_value val = syminfo.value ();
417 
418  str = val.type_name ();
419  param_length(pos_t) = ((str.length ()
420  > static_cast<std::size_t> (param_length(pos_t)))
421  ? str.length () : param_length(pos_t));
422 
423  elements1 = val.numel ();
424  ss1 << elements1;
425  str = ss1.str ();
426  param_length(pos_e) = ((str.length ()
427  > static_cast<std::size_t> (param_length(pos_e)))
428  ? str.length () : param_length(pos_e));
429 
430  bytes1 = val.byte_size ();
431  ss2 << bytes1;
432  str = ss2.str ();
433  param_length(pos_b) = ((str.length ()
434  > static_cast<std::size_t> (param_length(pos_b)))
435  ? str.length () : param_length (pos_b));
436  }
437 
438  idx = 0;
439  while (static_cast<std::size_t> (idx) < format_len)
440  {
441  whos_parameter param;
442  param.command = '\0';
443 
444  if (format[idx] == '%')
445  {
446  param.modifier = 'r';
447  param.parameter_length = 0;
448 
449  int a = 0;
450  int b = -1;
451  int balance = 1;
452  unsigned int items;
453  std::size_t pos;
454  std::string cmd;
455 
456  // Parse one command from format
457  cmd = format.substr (idx, format.length ());
458  pos = cmd.find (';');
459  if (pos == std::string::npos)
460  error ("parameter without ; in format");
461 
462  cmd = cmd.substr (0, pos+1);
463 
464  idx += cmd.length ();
465 
466  // FIXME: use iostream functions instead of sscanf!
467 
468  if (cmd.find_first_of ("crl") != 1)
469  items = sscanf (cmd.c_str (), "%c%c:%d:%d:%d;",
470  &garbage, &param.command, &a, &b, &balance);
471  else
472  items = sscanf (cmd.c_str (), "%c%c%c:%d:%d:%d;",
473  &garbage, &param.modifier, &param.command,
474  &a, &b, &balance) - 1;
475 
476  if (items < 2)
477  error ("whos_line_format: found parameter structure without command");
478 
479  // Exception case of bare class command 'c' without modifier 'l/r'
480  if (param.modifier == 'c'
481  && param_string.find (param.command) == std::string::npos)
482  {
483  param.modifier = 'r';
484  param.command = 'c';
485  }
486 
487  // Insert data into parameter
488  param.first_parameter_length = 0;
489  pos = param_string.find (param.command);
490  if (pos == std::string::npos)
491  error ("whos_line_format: '%c' is not a command", param.command);
492 
493  param.parameter_length = param_length(pos);
494  param.text = param_names(pos);
495  param.line.assign (param_names(pos).length (), '=');
496 
497  param.parameter_length = (a > param.parameter_length
498  ? a : param.parameter_length);
499  if (param.command == 's' && param.modifier == 'c' && b > 0)
500  param.first_parameter_length = b;
501 
502  if (param.command == 's')
503  {
504  // Have to calculate space needed for printing
505  // matrix dimensions Space needed for Size column is
506  // hard to determine in prior, because it depends on
507  // dimensions to be shown. That is why it is
508  // recalculated for each Size-command int first,
509  // rest = 0, total;
510  int rest = 0;
511  int first = param.first_parameter_length;
512  int total = param.parameter_length;
513 
514  for (const auto& syminfo : m_lst)
515  {
516  octave_value val = syminfo.value ();
517  std::string dims_str = val.get_dims_str ();
518  int first1 = dims_str.find ('x');
519  int total1 = dims_str.length ();
520  int rest1 = total1 - first1;
521  rest = (rest1 > rest ? rest1 : rest);
522  first = (first1 > first ? first1 : first);
523  total = (total1 > total ? total1 : total);
524  }
525 
526  if (param.modifier == 'c')
527  {
528  if (first < balance)
529  first += balance - first;
530  if (rest + balance < param.parameter_length)
531  rest += param.parameter_length - rest - balance;
532 
533  param.parameter_length = first + rest;
534  param.first_parameter_length = first;
535  param.balance = balance;
536  }
537  else
538  {
539  param.parameter_length = total;
540  param.first_parameter_length = 0;
541  }
542  }
543  else if (param.modifier == 'c')
544  error ("whos_line_format: modifier 'c' not available for command '%c'",
545  param.command);
546 
547  // What happens if format contains negative numbers
548  // at param_length positions?
549  param.balance = (b < 0 ? 0 : param.balance);
550  param.first_parameter_length = (b < 0
551  ? 0
552  : param.first_parameter_length);
553  param.parameter_length = (a < 0
554  ? 0
555  : (param.parameter_length
556  < param_length(pos_s)
557  ? param_length(pos_s)
558  : param.parameter_length));
559 
560  params.push_back (param);
561  }
562  else
563  {
564  // Text string, to be printed as it is ...
565  std::string text;
566  std::size_t pos;
567  text = format.substr (idx, format.length ());
568  pos = text.find ('%');
569  if (pos != std::string::npos)
570  text = text.substr (0, pos);
571 
572  // Push parameter into list ...
573  idx += text.length ();
574  param.text=text;
575  param.line.assign (text.length (), ' ');
576  params.push_back (param);
577  }
578  }
579 
580  return params;
581 }
582 
583 OCTAVE_END_NAMESPACE(octave)
Definition: Cell.h:43
std::size_t length() const
Definition: base-list.h:53
std::list< symbol_info > m_lst
Definition: base-list.h:106
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
void assign(const std::string &k, const Cell &val)
Definition: oct-map.h:344
void assign(const std::string &k, const octave_value &val)
Definition: oct-map.h:230
std::string class_name() const
Definition: ov.h:1347
std::string get_dims_str() const
Matrix size()
Definition: ov.h:462
bool issparse() const
Definition: ov.h:753
octave_idx_type numel() const
Definition: ov.h:559
bool iscomplex() const
Definition: ov.h:741
std::string type_name() const
Definition: ov.h:1345
std::size_t byte_size() const
Definition: ov.h:562
void print_descriptor(std::ostream &os, const std::list< whos_parameter > params) const
Definition: syminfo.cc:249
std::list< std::string > names() const
Definition: syminfo.cc:182
void display(std::ostream &os, const std::string &format) const
Definition: syminfo.cc:334
std::list< whos_parameter > parse_whos_line_format(const std::string &format) const
Definition: syminfo.cc:366
octave_value varval(const std::string &name) const
Definition: syminfo.cc:170
octave_map map_value(const std::string &caller_function_name, int nesting_level) const
Definition: syminfo.cc:193
void display_line(std::ostream &os, const std::list< whos_parameter > &params) const
Definition: syminfo.cc:46
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void() error(const char *fmt,...)
Definition: error.cc:988
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
#define octave_stdout
Definition: pager.h:309
char modifier
Definition: syminfo.h:45
int parameter_length
Definition: syminfo.h:46
std::string line
Definition: syminfo.h:50
std::string text
Definition: syminfo.h:49
int first_parameter_length
Definition: syminfo.h:47
char command
Definition: syminfo.h:44
std::size_t format(std::ostream &os, const char *fmt,...)
F77_RET_T len
Definition: xerbla.cc:61