Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RDFDisplay.cxx
Go to the documentation of this file.
1 #include "ROOT/RDF/RDisplay.hxx"
2 #include "TInterpreter.h"
3 
4 #include <iomanip>
5 #include <limits>
6 
7 namespace ROOT {
8 namespace Internal {
9 namespace RDF {
10 
11 
12 /**
13  * \class ROOT::Internal::RDF::RDisplayElement
14  * \ingroup dataframe
15  * Helper class to let Display print compact tabular representations of the events
16  *
17  * This class is internal and not meant to be explicitly instantiated by the user.
18  * It is needed during printing to understand if a value can be
19  * skipped or must be printed. Each RDisplayElement represents a cell.
20  */
21 
22 ////////////////////////////////////////////////////////////////////////////
23 /// Constructor
24 /// \param[in] representation The representation string
25 RDisplayElement::RDisplayElement(const std::string &representation) : fRepresentation(representation)
26 {
27  SetPrint();
28 }
29 
30 ////////////////////////////////////////////////////////////////////////////
31 /// Constructor assuming an empty representation to be printed
32 RDisplayElement::RDisplayElement()
33 {
34  SetPrint();
35 }
36 
37 ////////////////////////////////////////////////////////////////////////////
38 /// Flag this cell as to be printed
39 void RDisplayElement::SetPrint()
40 {
41  fPrintingAction = PrintingAction::ToBePrinted;
42 }
43 
44 ////////////////////////////////////////////////////////////////////////////
45 /// Flag this cell as to be skipped
46 void RDisplayElement::SetIgnore()
47 {
48  fPrintingAction = PrintingAction::ToBeIgnored;
49 }
50 
51 ////////////////////////////////////////////////////////////////////////////
52 /// Flag this cell to be replaced by "..."
53 void RDisplayElement::SetDots()
54 {
55  fPrintingAction = PrintingAction::ToBeDotted;
56 }
57 
58 ////////////////////////////////////////////////////////////////////////////
59 /// Return if the cell has to be printed
60 bool RDisplayElement::IsPrint() const
61 {
62  return fPrintingAction == PrintingAction::ToBePrinted;
63 }
64 
65 ////////////////////////////////////////////////////////////////////////////
66 /// Return if the cell has to be skipped
67 bool RDisplayElement::IsIgnore() const
68 {
69  return fPrintingAction == PrintingAction::ToBeIgnored;
70 }
71 
72 ////////////////////////////////////////////////////////////////////////////
73 /// Return if the cell has to be replaced by "..."
74 bool RDisplayElement::IsDot() const
75 {
76  return fPrintingAction == PrintingAction::ToBeDotted;
77 }
78 
79 const std::string &RDisplayElement::GetRepresentation() const
80 {
81  return fRepresentation;
82 }
83 
84 bool RDisplayElement::IsEmpty() const
85 {
86  return fRepresentation.empty();
87 }
88 
89 } // namespace RDF
90 } // namespace Internal
91 
92 namespace RDF {
93 
94 void RDisplay::EnsureCurrentColumnWidth(size_t w)
95 {
96  // If the current element is wider than the widest element found, update the width
97  if (fWidths[fCurrentColumn] < w) {
98  if (w > std::numeric_limits<unsigned short>::max()) {
99  w = std::numeric_limits<unsigned short>::max();
100  }
101  fWidths[fCurrentColumn] = (unsigned short) w;
102  }
103 }
104 
105 void RDisplay::AddToRow(const std::string &stringEle)
106 {
107  // If the current element is wider than the widest element found, update the width
108  EnsureCurrentColumnWidth(stringEle.length());
109 
110  // Save the element...
111  fTable[fCurrentRow][fCurrentColumn] = DElement_t(stringEle);
112 
113  // ...and move to the next
114  MovePosition();
115 }
116 
117 void RDisplay::AddCollectionToRow(const std::vector<std::string> &collection)
118 {
119  auto row = fCurrentRow;
120  // For each element of the collection, save it. The first element will be in the current row, next ones will have
121  // their own row.
122  size_t collectionSize = collection.size();
123  for (size_t index = 0; index < collectionSize; ++index) {
124  auto stringEle = collection[index];
125  auto element = DElement_t(stringEle);
126 
127  // Update the width if this element is the biggest found
128  EnsureCurrentColumnWidth(stringEle.length());
129 
130  if (index == 0 || index == collectionSize - 1) {
131  // Do nothing, by default DisplayElement is printed
132  } else if (index == 1) {
133  element.SetDots();
134  // Be sure the "..." fit
135  EnsureCurrentColumnWidth(3);
136  } else {
137  // In the Print(), after the dots, all element will just be ignored except the last one.
138  element.SetIgnore();
139  }
140 
141  // Save the element
142  fTable[row][fCurrentColumn] = element;
143  ++row;
144 
145  if (index != collectionSize - 1 && fTable.size() <= row) {
146  // This is not the last element, prepare the next row for the next element, if not already done by another
147  // collection
148  fTable.push_back(std::vector<DElement_t>(fNColumns));
149  }
150  }
151  fNextRow = (fNextRow > row) ? fNextRow : row;
152  MovePosition();
153 }
154 
155 void RDisplay::MovePosition()
156 {
157  // Go to the next element. If it is outside the row, just go the first element of the next row.
158  ++fCurrentColumn;
159  if (fCurrentColumn == fNColumns) {
160  fCurrentRow = fNextRow;
161  fCurrentColumn = 0;
162  fNextRow = fCurrentRow + 1;
163  fTable.push_back(std::vector<DElement_t>(fNColumns));
164  }
165 }
166 
167 RDisplay::RDisplay(const VecStr_t &columnNames, const VecStr_t &types, int entries)
168  : fTypes(types), fWidths(columnNames.size(), 0), fRepresentations(columnNames.size()),
169  fCollectionsRepresentations(columnNames.size()), fNColumns(columnNames.size()), fEntries(entries)
170 {
171 
172  // Add the first row with the names of the columns
173  fTable.push_back(std::vector<DElement_t>(columnNames.size()));
174  for (auto name : columnNames) {
175  AddToRow(name);
176  }
177 }
178 
179 size_t RDisplay::GetNColumnsToShorten() const
180 {
181  size_t totalWidth = 0;
182 
183  auto size = fWidths.size();
184  for (size_t i = 0; i < size; ++i) {
185  totalWidth += fWidths[i];
186  if (totalWidth > fgMaxWidth) {
187  return size - i;
188  }
189  }
190 
191  return 0;
192 }
193 
194 void RDisplay::Print() const
195 {
196  auto columnsToPrint =
197  fNColumns - GetNColumnsToShorten(); // Get the number of columns that fit in the characters limit
198  std::vector<bool> hasPrintedNext(fNColumns,
199  false); // Keeps track if the collection as already been shortened, allowing to skip
200  // all elements until the next printable element.
201  auto nrRows = fTable.size();
202  for (size_t rowIndex = 0; rowIndex < nrRows; ++rowIndex) {
203  auto &row = fTable[rowIndex];
204 
205  std::stringstream stringRow;
206  bool isRowEmpty = true; // It may happen during compacting that some rows are empty, this happens for example if
207  // collections have different size. Thanks to this flag, these rows are just ignored.
208  for (size_t columnIndex = 0; columnIndex < columnsToPrint; ++columnIndex) {
209  const auto &element = row[columnIndex];
210  std::string printedElement = "";
211 
212  if (element.IsDot()) {
213  printedElement = "...";
214  } else if (element.IsPrint()) {
215  // Maybe the element is part of a collection that is being shortened, and so it was already printed.
216  if (!hasPrintedNext[columnIndex]) {
217  printedElement = element.GetRepresentation();
218  }
219  hasPrintedNext[columnIndex] =
220  false; // Encountered "next printable element", shortening can start again when needed.
221  } else { // IsIgnore
222  // Shortening is starting here. Print directly the last element, to have something like 1 ... 3, and don't
223  // print anything else.
224  if (!hasPrintedNext[columnIndex]) {
225  size_t i = rowIndex + 1; // Starting from the next row...
226  for (; !fTable[i][columnIndex].IsPrint(); ++i) {
227  // .. look for the first element that can be printed, it will be the last of the collection.
228  }
229  printedElement = fTable[i][columnIndex].GetRepresentation(); // Print the element
230  hasPrintedNext[columnIndex] = true; // And start ignoring anything else until the next collection.
231  }
232  }
233  if (!printedElement.empty()) {
234  // Found at least one element, so the row is not empty.
235  isRowEmpty = false;
236  }
237 
238  stringRow << std::left << std::setw(fWidths[columnIndex]) << std::setfill(fgSeparator) << printedElement
239  << " | ";
240  }
241  if (!isRowEmpty) {
242  std::cout << stringRow.str() << std::endl;
243  }
244  }
245 }
246 
247 std::string RDisplay::AsString() const
248 {
249  // This method works as Print() but without any check on collection. It just returns a string with the whole
250  // representation
251  std::stringstream stringRepresentation;
252  for (auto row : fTable) {
253  for (size_t i = 0; i < row.size(); ++i) {
254  stringRepresentation << std::left << std::setw(fWidths[i]) << std::setfill(fgSeparator)
255  << row[i].GetRepresentation() << " | ";
256  }
257  stringRepresentation << "\n";
258  }
259  return stringRepresentation.str();
260 }
261 
262 } // namespace RDF
263 } // namespace ROOT