ztsdb
display.hpp
1 // (C) 2016 Leonardo Silvestri
2 //
3 // This file is part of ztsdb.
4 //
5 // ztsdb is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // ztsdb is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with ztsdb. If not, see <http://www.gnu.org/licenses/>.
17 
18 
19 #ifndef DISPLAY_HPP
20 #define DISPLAY_HPP
21 
22 
23 #include <limits>
24 #include "array.hpp"
25 #include "valuevar.hpp"
26 #include "zts.hpp"
27 #include "config.hpp"
28 #include "index.hpp"
29 
30 
31 namespace val {
32 
33  template<typename T>
34  string to_string(T t, const cfg::CfgMap& cfg);
35  string to_string(const VCode& v, const cfg::CfgMap& cfg);
36  string to_string(const std::shared_ptr<VClos>& v, const cfg::CfgMap& cfg);
37  string to_string(const VClos& v, const cfg::CfgMap& cfg=cfg::cfgmap);
38  string to_string(const VNull& v, const cfg::CfgMap& cfg);
39  string to_string(const std::shared_ptr<VBuiltinG>& v, const cfg::CfgMap& cfg);
40  string to_string(const SpFuture& v, const cfg::CfgMap& cfg);
41  string to_string(const VNamed& v, const cfg::CfgMap& cfg);
42  string to_string(const VConn& conn, const cfg::CfgMap& cfg);
43  string to_string(const SpTimer& v, const cfg::CfgMap& cfg);
44  string to_string(const VList& l, const cfg::CfgMap& cfg);
45  string to_string(const SpVList& l, const cfg::CfgMap& cfg);
46  string to_string(double d, const cfg::CfgMap& cfg);
47  string to_string(bool, const cfg::CfgMap& cfg);
48  string to_string(const arr::zts& ts, const cfg::CfgMap& cfg);
49  string to_string(const SpZts& ts, const cfg::CfgMap& cfg);
50  string to_string(Global::dtime dt, const cfg::CfgMap& cfg, bool unquoted=false);
51  string to_string(Global::dtime::duration d, const cfg::CfgMap& cfg);
52  string to_string(tz::interval i, const cfg::CfgMap& cfg);
53  string to_string(tz::period p, const cfg::CfgMap& cfg);
54  string to_string(const string& s, const cfg::CfgMap& cfg, bool unquoted=false);
55  string to_string(const val::integer_t& s, const cfg::CfgMap& cfg);
56  string to_string(const val::SpVI& s, const cfg::CfgMap& cfg);
57  string to_string(const arr::zstring& s, const cfg::CfgMap& cfg, bool unquoted=false);
58  string to_string(const VError& e, const cfg::CfgMap& cfg);
59  string to_string(const VPtr& p, const cfg::CfgMap& cfg);
60 
61  using namespace std::string_literals;
62 
63  // arrays -------------------------------------------------------
64 
65 
66  // ---
67  template<typename T>
68  inline Vector<zstring> vectorToString(const Vector<T>& v, const cfg::CfgMap& cfg) {
69  Vector<zstring> res;
70  transform(v.begin(), v.end(), back_inserter(res),
71  [cfg](const T& t) { return to_string(t, cfg); });
72  return res;
73  }
74 
75  template<>
76  Vector<zstring> vectorToString(const Vector<double>& v, const cfg::CfgMap& cfg);
77 
78  template<>
79  Vector<zstring> vectorToString(const Vector<Global::dtime>& v, const cfg::CfgMap& cfg);
80 
81  template<>
82  Vector<zstring> vectorToString(const Vector<tz::interval>& v, const cfg::CfgMap& cfg);
83 
84  template<>
85  Vector<zstring> vectorToString(const Vector<tz::period>& v, const cfg::CfgMap& cfg);
86 
87  template<typename T>
88  struct ToString {
89  ToString(const cfg::CfgMap& cfg_p) : cfg(cfg_p) { }
90  Vector<zstring> operator()(Vector<T> v) { return vectorToString(v, cfg); }
91  const cfg::CfgMap& cfg;
92  };
93 
94  template<typename T>
95  inline Array<zstring> arrayToString(const Array<T>& a, const cfg::CfgMap& cfg) {
96  return Array<zstring>(a, ToString<T>(cfg), true);
97  }
98 
99  template<>
100  Array<zstring> arrayToString(const Array<double>& a, const cfg::CfgMap& cfg);
101 
102  template<>
103  Array<zstring> arrayToString(const Array<Global::dtime>& a, const cfg::CfgMap& cfg);
104 
105  template<>
106  Array<zstring> arrayToString(const Array<tz::interval>& a, const cfg::CfgMap& cfg);
107 
108  template<>
109  Array<zstring> arrayToString(const Array<tz::period>& a, const cfg::CfgMap& cfg);
110 
111  template<typename T>
112  Vector<zstring> getDimnames(const Array<T>&a,
113  idx_type d,
114  idx_type n,
115  const string& prefix="",
116  const string& postfix="") {
117  if (a.names.size() > d && a.hasNames(d)) {
118  return Vector<zstring>(a.names[d]->names.begin(), a.names[d]->names.begin()+n);
119  } else {
120  Vector<zstring> vs;
121  for (idx_type j=0; j<n; ++j) {
122  vs.push_back("[" + prefix + std::to_string(j+1) + postfix + "]");
123  }
124  return vs;
125  }
126  }
127 
128  inline Vector<zstring> getVectorLineNumbers(idx_type n, idx_type ncols) {
129  Vector<zstring> vs;
130  auto nrows = n / ncols;
131  if (n % ncols) {
132  ++nrows;
133  }
134  for (idx_type j=0; j<nrows; ++j) {
135  vs.push_back("[" + std::to_string(1 + j*ncols) + "]");
136  }
137  return vs;
138  }
139 
140  inline vector<unsigned> getLengths(const Vector<zstring> vs) {
141  auto vl = vector<unsigned>();
142  transform(vs.begin(), vs.end(), back_inserter(vl), [](string s){ return s.length(); });
143  return vl;
144  }
145 
146  template<typename T>
147  string displayVector(const Array<T>&a_p, const cfg::CfgMap& cfg) {
148  unsigned cfgWidth = static_cast<size_t>(get<int64_t>(cfg.get("width")));
149  auto cfgMaxPrint = static_cast<arr::idx_type>(get<int64_t>(cfg.get("max.print")));
150 
151  auto a = a_p.size() > cfgMaxPrint ? a_p.subsetRows(cfgMaxPrint) : a_p;
152 
153  stringstream ss;
154  idx_type n = min(a.dim[0], cfgMaxPrint);
155  auto vs = vectorToString(*a.v[0], cfg);
156 
157  auto lenValues = getLengths(vs);
158 
159  auto colstring = a.hasNames(0) ? getDimnames(a, 0, n) : Vector<zstring>();
160  unsigned colWidth;
161  if (a.hasNames(0)) {
162  auto lenNames = getLengths(colstring);
163  colWidth = std::max(*max_element(lenNames.begin(), lenNames.end()),
164  *max_element(lenValues.begin(), lenValues.end())) + 1;
165  } else {
166  colWidth = *max_element(lenValues.begin(), lenValues.end()) + 1;
167  }
168 
169  // figure out the line breaks iteratively:
170  auto ncols = min(cfgWidth / colWidth, static_cast<unsigned>(n));
171  if (!ncols) ++ncols; // we have to display something!
172  auto vln = getVectorLineNumbers(n, ncols);
173  auto lenVln = getLengths(vln);
174  auto vlnWidth = *max_element(lenVln.begin(), lenVln.end());
175  while (ncols > 1 && vlnWidth + ncols*colWidth > cfgWidth) {
176  --ncols; // it now doesn't fit anymore, so decrease ncol
177  vln = getVectorLineNumbers(n, ncols);
178  lenVln = getLengths(vln);
179  vlnWidth = *max_element(lenVln.begin(), lenVln.end());
180  }
181  auto nrows = n / ncols;
182  if (n % ncols) ++nrows;
183  for (unsigned j=0; j<nrows; ++j) {
184  if (a.hasNames(0)) {
185  // print the names:
186  ss.width(vlnWidth);
187  ss << "";
188  for (unsigned k=0; k<ncols; ++k) {
189  ss << ' ';
190  if (k+1 + j*ncols < n) {
191  ss.width(colWidth-1);
192  ss << left << colstring[k + j*ncols];
193  }
194  else {
195  ss << left << colstring[k + j*ncols];
196  break;
197  }
198  }
199  ss << endl;
200  }
201  // print the data:
202  ss.width(vlnWidth);
203  ss << right << vln[j];
204  for (unsigned k=0; k<ncols; ++k) {
205  ss << ' ';
206  if (k+1 + j*ncols < n) {
207  ss.width(colWidth-1);
208  ss << left << vs[k + j*ncols];
209  }
210  else {
211  ss << left << vs[k + j*ncols];
212  break;
213  }
214  }
215  if (j<nrows-1) ss << endl; // no trailing line break
216  }
217 
218  // if we didn't print everything, then let the user know
219  if (n < a_p.dim[0]) {
220  ss << endl << " [ reached getOption(""max.print"") -- omitted " <<
221  a_p.dim[0] - n << " entries ]";
222  }
223 
224  return ss.str();
225  }
226 
227  // MAXIDX is used to indicate we have a zero index, which needs to
228  // be differentiated so as to display '0' and not '1'!
229  const idx_type MAXIDX = std::numeric_limits<idx_type>::max();
230  inline vector<Index> getFirstVIndex(const arr::Vector<idx_type>& dim, idx_type maxrows) {
231  vector<Index> fi;
232  if (dim.size() < 2) {
233  throw std::out_of_range("getFirstVIndex(): dim.size() < 2");
234  }
235  if (maxrows < dim[0]) {
236  Vector<size_t> v(std::max(static_cast<idx_type>(1), maxrows));
237  std::iota(v.begin(), v.end(), 0);
238  fi.push_back(IntIndex(v));
239  fi.push_back(NullIndex{dim[1]});
240  } else {
241  fi.push_back(NullIndex{dim[0]});
242  fi.push_back(NullIndex{dim[1]});
243  }
244  for (idx_type j=2; j<dim.size(); ++j) {
245  fi.push_back(IntIndex(Vector<size_t>{ dim[j] ? 0 : size_t(MAXIDX) }));
246  }
247  return fi;
248  }
249 
250  inline bool getNextVIndex(vector<Index>& i, const arr::Vector<idx_type>& dim) {
251  if (dim.size() < 2) {
252  throw std::out_of_range("getNextVIndex(): dim.size() < 2");
253  }
254  if (i.size() != dim.size()) {
255  throw std::out_of_range("getNextVIndex(): index and dim sizes mismatch");
256  }
257  for (idx_type j=dim.size()-1; j>=2; --j) {
258  if (get<IntIndex>(i[j].idx).vi[0] == MAXIDX) {
259  continue;
260  } else if (get<IntIndex>(i[j].idx).vi[0] + 1 >= dim[j]) {
261  auto& ref = get<IntIndex>(i[j].idx);
262  arr::setv(ref.vi, 0, 0UL);
263  } else {
264  auto& ref = get<IntIndex>(i[j].idx);
265  arr::setv(ref.vi, 0, (ref.vi)[0]+1);
266  return true;
267  }
268  }
269  return false;
270  }
271 
272  inline string displaySliceHeader(const vector<Index>& ii, const vector<unique_ptr<Dname>>& names) {
273  stringstream ss;
274  if (ii.size() < 2) {
275  throw std::out_of_range("displaySliceHeader(): ii.size() < 3");
276  }
277  ss << ", ";
278  for (idx_type j=2; j<ii.size(); ++j) {
279  auto idx = get<IntIndex>(ii[j].idx).vi[0];
280  if (j < names.size()) {
281  ss << ", " << (idx == MAXIDX ? "0" :
282  (names[j]->size() ? (*names[j])[idx] : std::to_string(idx+1)));
283  }
284  }
285  ss << "\n";
286  return ss.str();
287  }
288 
289  template<typename T, typename R>
290  string displaySlice(const Array<T>& slice,
291  const Vector<R>& rownames_c,
292  const cfg::CfgMap& cfg,
293  idx_type& nleft)
294  {
295  auto cfgWidth = static_cast<size_t>(get<int64_t>(cfg.get("width")));
296 
297  stringstream ss;
298 
299  auto nrows = min(nleft / std::max(slice.dim[1], static_cast<idx_type>(1)), slice.dim[0]);
300  auto rownames = Vector<zstring>(nrows);
301  if (rownames_c.size() == 0) {
302  for (idx_type j=0; j<nrows; ++j) {
303  arr::setv(rownames, j, arr::zstring("[" + std::to_string(j+1) + ",]"));
304  }
305  } else {
306  for (idx_type j=0; j<nrows; ++j) {
307  arr::setv(rownames, j, arr::zstring(to_string(rownames_c[j], cfg, true)));
308  }
309  }
310 
311  auto lenRownames = getLengths(rownames);
312  auto colnames = getDimnames(slice, 1, min(nleft, slice.dim[1]), ",");
313  auto lenColnames = getLengths(colnames);
314  auto data = arrayToString(slice, cfg);
315  auto lenData = applyf<arr::zstring, unsigned>(data, [](const arr::zstring& s){ return s.length(); });
316  auto colWidths = maxcol(lenData);
317  for (idx_type j=0; j<lenColnames.size(); ++j) {
318  arr::setv(colWidths, j, std::max(colWidths[j], lenColnames[j]));
319  }
320  colWidths = applyf<unsigned, unsigned>(colWidths, [](unsigned u) { return ++u; });
321  auto rownamesWidth = lenRownames.size() ?
322  *max_element(lenRownames.begin(), lenRownames.end()) : 0;
323 
324  idx_type colStart = 0;
325  while (colStart < colnames.size()) {
326  // figure out where we need to line break:
327  idx_type colEnd = colStart + 1; // print at least one!
328  unsigned nchar = rownamesWidth + colWidths[colEnd-1];
329  while (colEnd < colnames.size()) { // use colnames in case we are truncating the columns
330  nchar += colWidths[colEnd];
331  if (nchar > cfgWidth) {
332  break;
333  } else {
334  ++colEnd;
335  }
336  }
337  // print the column header:
338  ss.width(rownamesWidth);
339  ss << "";
340  for (idx_type col=colStart; col<colEnd; ++col) {
341  ss.width(colWidths[col]);
342  ss << colnames[col];
343  }
344  // if at the end but not all the columns printed, print an ellipsis:
345  if (colEnd == colnames.size() && colEnd < slice.dim[1]) {
346  ss << " ...";
347  }
348  ss << endl;
349  // print the data:
350  for (idx_type row=0; row<rownames.size(); ++row) {
351  ss.width(rownamesWidth);
352  ss << (rownames_c.size() ? left : right) << rownames[row] << right;
353  for (idx_type col=colStart; col<colEnd; ++col) {
354  ss << " ";
355  ss.width(colWidths[col]-1);
356  ss << left << data[row + col * slice.dim[0]] << right;
357  }
358  ss << endl;
359  }
360  colStart = colEnd;
361  }
362 
363  nleft -= nrows * std::max(slice.dim[1], static_cast<idx_type>(1));
364  return ss.str().substr(0, ss.str().length()-1); // pull out trailing line break
365  }
366 
367 
368  // we could probably slice with zeros and consolidate this function
369  // and the displaySlice... LLL
370  template<typename R> // R: row names type
371  string displaySliceWithZeros(const vector<Index>& i,
372  const arr::Vector<idx_type>& dim,
373  const vector<unique_ptr<Dname>>& names,
374  const Vector<R>& rownames_c,
375  const cfg::CfgMap& cfg,
376  idx_type& nleft)
377  {
378  stringstream ss;
379 
380  auto nrows = min(nleft / std::max(dim[1], static_cast<idx_type>(1)), dim[0]);
381  auto rownames = Vector<zstring>(nrows);
382  if (rownames_c.size() == 0) {
383  for (idx_type j=0; j<nrows; ++j) {
384  arr::setv(rownames, j, arr::zstring("[" + std::to_string(j+1) + ",]"));
385  }
386  } else {
387  for (idx_type j=0; j<nrows; ++j) {
388  arr::setv(rownames, j, arr::zstring(to_string(rownames_c[j], cfg, true)));
389  }
390  }
391  auto lenRownames = getLengths(rownames);
392  auto rownamesWidth = lenRownames.size() ?
393  *max_element(lenRownames.begin(), lenRownames.end()) : 0;
394 
395  auto ncols = min(nleft, std::max(dim[1], static_cast<idx_type>(1)));
396  auto colnames = names[1]->names;
397  if (colnames.size() == 0) {
398  for (idx_type j=0; j<ncols; ++j) {
399  colnames.push_back("[," + std::to_string(j+1) + "]");
400  }
401  } else {
402  colnames.resize(ncols);
403  }
404  auto lenColnames = getLengths(colnames);
405  auto colnamesWidth = lenColnames;
406  for_each(colnamesWidth.begin(), colnamesWidth.end(), [](unsigned& x) { ++x; });
407 
408  idx_type colStart = 0;
409  auto cfgWidth = static_cast<size_t>(get<int64_t>(cfg.get("width")));
410  while (colStart < colnames.size()) {
411  // figure out where we need to line break:
412  idx_type colEnd = colStart + 1; // print at least one!
413  unsigned nchar = rownamesWidth + lenColnames[colEnd-1];
414  while (colEnd < colnames.size()) { // use colnames in case we are truncating the columns
415  nchar += colnamesWidth[colEnd];
416  if (nchar > cfgWidth) {
417  break;
418  } else {
419  ++colEnd;
420  }
421  }
422  if (dim[1]) {
423  // print the column header:
424  ss.width(rownamesWidth);
425  ss << "";
426  for (idx_type col=colStart; col<colEnd; ++col) {
427  ss.width(colnamesWidth[col]);
428  ss << colnames[col];
429  }
430  // if at the end but not all the columns printed, print an ellipsis:
431  if (colEnd == colnames.size() && colEnd < dim[1]) {
432  ss << " ...";
433  }
434  ss << endl;
435  }
436  // print the rownames:
437  for (idx_type row=0; row<rownames.size(); ++row) {
438  ss.width(rownamesWidth);
439  ss << (rownames_c.size() ? left : right) << rownames[row] << right;
440  ss << endl;
441  }
442  colStart = colEnd;
443  }
444 
445  nleft -= nrows * ncols;
446 
447  return ss.str().substr(0, ss.str().length()-1); // pull out trailing line break
448  }
449 
450 
451  template<typename T, typename R>
452  string display(const Array<T>& a,
453  const Vector<R>& rownames,
454  const cfg::CfgMap& cfg,
455  size_t& left) {
456  auto cfgMaxPrint = static_cast<size_t>(get<int64_t>(cfg.get("max.print")));
457 
458  stringstream ss;
459 
460  if (!a.dim.size()) {
461  throw domain_error("array with no dimensions");
462  }
463 
464  // if all dimensions are 0 just display that:
465  if (all_of(a.dim.begin(), a.dim.end(), [](idx_type x) { return x==0; })) {
466  ss << arr::TypeName<T>::s << '(';
467  copy(a.dim.begin(), a.dim.end() - 1, ostream_iterator<idx_type>(ss, "x"));
468  ss << a.dim.back();
469  ss << ")";
470  return ss.str();
471  }
472 
473  // the one dimentional case really has a set of rules of its own,
474  // so treat it separately:
475  if (a.dim.size() == 1) {
476  return displayVector(a, cfg); // give left/rows LLL
477  }
478 
479  // if we have a 0 dimension somewhere but with other non 0
480  // dimensions, we only print header and row/col name information;
481  // it's a special case, so treat is separately:
482  bool hasZeros = std::any_of(a.dim.begin(), a.dim.end(), [](idx_type x) { return x==0; });
483 
484  // replace dimensions of size 0 with 1 so we can calculate
485  // correctly what we need to display (for example, if we have
486  // columns==0, we will still display the rows, so we will display
487  // rows x 1):
488  auto dim1 = a.dim;
489  for_each(dim1.begin(), dim1.end(), [](idx_type& x) { if (!x) x = 1; });
490 
491  // how many slices?:
492  idx_type totslices, nslices, ommittedSlices;
493  idx_type sliceSize = dim1[0] * dim1[1];
494  idx_type tot = accumulate(dim1.begin(), dim1.end(), 1, std::multiplies<idx_type>());
495  if (a.dim.size() == 2) {
496  totslices = nslices = 1;
497  ommittedSlices = 0;
498  } else {
499  totslices = accumulate(dim1.begin()+2, dim1.end(), 1, std::multiplies<idx_type>());
500  nslices = min(totslices, cfgMaxPrint / sliceSize);
501  if (min(tot, static_cast<idx_type>(cfgMaxPrint)) % sliceSize) {
502  ++nslices; // the slice is not ommitted, it's partially printed
503  }
504  ommittedSlices = totslices - nslices;
505  }
506 
507  auto nleft = min(tot, left);
508  idx_type ommittedRows = tot <= left ? 0 : (dim1[0] - nleft % sliceSize / dim1[1]);
509  if (cfgMaxPrint >= dim1[1]) {
510  ommittedRows %= dim1[0];
511  }
512 
513  idx_type maxrows = min(dim1[0], nleft / dim1[1]);
514  auto vi = getFirstVIndex(a.dim, maxrows);
515  for (idx_type k=0; k<nslices; ++k) {
516  if (totslices > 1) {
517  ss << displaySliceHeader(vi, a.names) << endl;
518  }
519  if (hasZeros) {
520  ss << displaySliceWithZeros(vi, a.dim, a.names, rownames, cfg, nleft) << endl;
521  } else {
522  // drop=false, because we don't want to drop to a vector;
523  // displaySlice handles correctly trailing dims of size 1:
524  auto slice = a(vi, false);
525  ss << displaySlice(slice, rownames, cfg, nleft) << endl;
526  }
527  if (totslices > 1) {
528  ss << endl;
529  }
530  getNextVIndex(vi, dim1);
531  }
532  left = tot < left ? left - tot : 0;
533 
534 
535  // if we didn't print everything, then let the user know
536  if (ommittedRows && ommittedSlices) {
537  ss << " [ reached getOption(""max.print"") -- omitted "
538  << ommittedRows << " row(s) and " << ommittedSlices << " slice(s) ]" << endl;
539  } else if (ommittedRows) {
540  ss << " [ reached getOption(""max.print"") -- omitted "
541  << ommittedRows << " row(s) ]" << endl;
542  } else if (ommittedSlices) {
543  ss << " [ reached getOption(""max.print"") -- omitted "
544  << ommittedSlices << " slice(s) ]" << endl;
545  }
546 
547  return ss.str().substr(0, ss.str().length()-1); // pull out trailing line break
548  }
549 
550 
551  string display(const SpVList& l, const cfg::CfgMap& cfg, string prefix, size_t& left);
552 
553  template<typename T>
554  const string to_string(const Array<T>& v, const cfg::CfgMap& cfg) {
555  size_t left = static_cast<arr::idx_type>(get<int64_t>(cfg.get("max.print")));
556  return display(v, v.names[0]->names, cfg, left);
557  }
558 
559  template<typename T>
560  const string to_string(const cow_ptr<Array<T>>& v,
561  const cfg::CfgMap& cfg) {
562  size_t left = static_cast<arr::idx_type>(get<int64_t>(cfg.get("max.print")));
563  return display(*v, v->names[0]->names, cfg, left);
564  }
565 
566 
567  // ---------------------------
568  // to_string - visitor to print out values:
569  struct to_string_v {
570  typedef string result_type;
571 
572  template <typename T>
573  string operator()(const T& t, const cfg::CfgMap& cfg) const {
574  return to_string(t, cfg);
575  }
576  };
577 
578  inline string to_string(const val::Value& v, const cfg::CfgMap& cfg=cfg::cfgmap) {
579  return apply_visitor(to_string_v(), v, cfg);
580  }
581 
582  string display(const val::Value& v);
583 
584  // str --------------------------
585  string str(const val::Value& v, const cfg::CfgMap& cfg, std::string prefix="");
586 
587  // visitor to print out short descritption of values:
588  template <typename T>
589  string str(const T& v, const cfg::CfgMap& cfg, std::string prefix) {
590  auto cfgWidth = static_cast<size_t>(get<int64_t>(cfg.get("width")));
591 
592  stringstream ss;
593  ss << ' ' << val::Typeof()(v);
594  if (v.isOrdered()) {
595  ss << " - ord";
596  }
597  if (!v.isScalar()) {
598  // dimensions:
599  ss << " [";
600  for (arr::idx_type i=0; i<v.getdim().size(); ++i) {
601  stringstream dims;
602  dims << "1:" << v.getdim(i);
603  if (i != v.getdim().size()-1) {
604  dims << ", ";
605  }
606  if (ss.str().size() + dims.str().size() > cfgWidth-4) {
607  ss << "...";
608  break;
609  }
610  else {
611  ss << dims.str();
612  }
613  }
614  ss << "]";
615  }
616  ss << ' ';
617  // elts
618  for (arr::idx_type i=0; i<v.size(); ++i) {
619  stringstream elt;
620  elt << to_string(v[i], cfg);
621  if (ss.str().size() + elt.str().size() > cfgWidth-4) {
622  ss << "...";
623  break;
624  }
625  else {
626  ss << elt.str();
627  if (i != v.size()-1) ss << ' ';
628  }
629  }
630  // dimnames:
631  // build a vlist:
632  bool hasDimNames = false;
633  auto dimnames = make_cow<val::VList>(false);
634  for (arr::idx_type i=0; i<v.getdim().size(); ++i) {
635  if (v.hasNames(i)) {
636  auto dimarray = make_cow<val::VArrayS>(false,
637  arr::Vector<arr::idx_type>{v.getdim(i)},
638  v.getNames(i).names);
639  dimnames->push_back(std::make_pair(arr::zstring(""), val::Value(dimarray)));
640  hasDimNames = true;
641  }
642  else {
643  dimnames->push_back(std::make_pair(arr::zstring(""), val::VNull()));
644  }
645  }
646  if (hasDimNames) {
647  ss << std::endl << prefix << " - dimnames =" << str(val::Value(dimnames), cfg, prefix + " ..");
648  }
649  ss << std::endl << prefix << " - " << v.getAllocFactory().to_string();
650 
651  return ss.str();
652  }
653 
654  template <>
655  string str(const val::VList& vl, const cfg::CfgMap& cfg, std::string prefix);
656 
657  template <>
658  string str(const arr::zts& z, const cfg::CfgMap& cfg, std::string prefix);
659 
660  template <>
661  string str(const val::VClos& vl, const cfg::CfgMap& cfg, std::string prefix);
662 
663 }
664 
665 
666 #endif
val::VNull
Definition: valuevar.hpp:75
arr::Array::size
idx_type size() const
Get the total number of elements in the array.
Definition: array.hpp:833
arr::cow_ptr
Definition: cow_ptr.hpp:42
tz::period
Definition: period.hpp:30
val::to_string_v
Definition: display.hpp:569
arr::Vector
Definition: vector_base.hpp:103
arr::ZString
Definition: string.hpp:33
val
Contains the types that constitute the output of an evaluation by the interpreter.
Definition: display.hpp:31
val::VCode
Code value. This type contains code (as a result).
Definition: valuevar.hpp:250
val::Typeof
Definition: valuevar.hpp:416
val::VClos
Definition: valuevar.hpp:284
arr::IntIndex_T
Definition: index.hpp:109
tz::interval
Definition: interval.hpp:31
val::VList
Definition: valuevar.hpp:360
arr::Array::names
vector< unique_ptr< Dname > > names
v is a set of cols, v[0], v[1] are the cols
Definition: array.hpp:1276
val::VNamed
Definition: valuevar.hpp:389
val::VError
Definition: valuevar.hpp:134
val::ToString
Definition: display.hpp:88
arr::zts
Definition: zts.hpp:35
val::VConn
Definition: valuevar.hpp:101
arr::Array::subsetRows
Array subsetRows(idx_type n, idx_type from=0, bool addrownums=false) const
Subset the specified row range:
Definition: array.hpp:734
arr::NullIndex
Definition: index.hpp:54
cfg::CfgMap
Definition: config.hpp:35
arr::Array
Definition: array.hpp:109
val::VPtr
Definition: valuevar.hpp:257