Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RDisplay.hxx
Go to the documentation of this file.
1 // Author: Enrico Guiraud, Danilo Piparo CERN, Massimo Tumolo Politecnico di Torino 08/2018
2 
3 /*************************************************************************
4  * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. *
5  * All rights reserved. *
6  * *
7  * For the licensing terms see $ROOTSYS/LICENSE. *
8  * For the list of contributors see $ROOTSYS/README/CREDITS. *
9  *************************************************************************/
10 
11 #ifndef ROOT_RDFDISPLAYER
12 #define ROOT_RDFDISPLAYER
13 
14 #include "ROOT/RDF/Utils.hxx"
15 #include "ROOT/TypeTraits.hxx"
16 #include "TClassEdit.h"
17 
18 #include <vector>
19 #include <string>
20 #include <iostream>
21 #include <sstream>
22 
23 namespace ROOT {
24 namespace Internal {
25 namespace RDF {
26 
27 template<typename T>
28 class DisplayHelper;
29 std::string PrettyPrintAddr(const void *const addr);
30 
31 class RDisplayElement {
32 private:
33  enum class PrintingAction { ToBePrinted, ToBeIgnored, ToBeDotted };
34  std::string fRepresentation;
35  PrintingAction fPrintingAction;
36 
37 public:
38  RDisplayElement(const std::string &representation);
39  RDisplayElement();
40  void SetPrint();
41  void SetIgnore();
42  void SetDots();
43  bool IsPrint() const;
44  bool IsIgnore() const;
45  bool IsDot() const;
46  const std::string &GetRepresentation() const;
47  bool IsEmpty() const;
48 };
49 } // namespace RDF
50 } // namespace Internal
51 
52 namespace RDF {
53 
54 /**
55  * \class ROOT::RDF::RDisplay
56  * \ingroup dataframe
57  * This class is the textual representation of the content of a columnar dataset.
58  *
59  * This class is provided to the user, and it can be used to print on screen
60  * the entries of the dataset requested through the Display action in a compact
61  * representation or to return the full representation of the events as a string.
62  * In order to apply proper formatting the content is buffered in memory as strings.
63  */
64 class RDisplay {
65  template<typename T>
66  friend class ROOT::Internal::RDF::DisplayHelper;
67 private:
68  using VecStr_t = std::vector<std::string>;
69  using DElement_t = ROOT::Internal::RDF::RDisplayElement;
70  static constexpr char fgSeparator = ' '; ///< Spacing used to align the table entries
71  static constexpr unsigned fgMaxWidth = 80;
72 
73  VecStr_t fTypes; ///< This attribute stores the type of each column. It is needed by the interpreter to print it.
74  std::vector<bool> fIsCollection; ///< True if the column contains a collection. Collections are treated differently
75  ///< during the printing.
76  std::vector<std::vector<DElement_t>> fTable; ///< String representation of the data to be printed.
77  std::vector<unsigned short> fWidths; ///< Tracks the maximum width of each column, based on the largest element.
78 
79  VecStr_t fRepresentations; ///< Used by the JITted code to store the string representation of the data.
80  std::vector<VecStr_t> fCollectionsRepresentations; ///< Used by the JITted code to store the string representation of
81  ///< the data in case of collection. Each row corresponds to a
82  ///< column, each column to a value of the collection.
83 
84  size_t fNColumns; ///< Number of columns to be printed
85 
86  size_t fCurrentRow = 0; ///< Row that is being filled
87  size_t fNextRow = 1; ///< Next row to be filled.
88  size_t fCurrentColumn = 0; ///< Column that is being filled.
89 
90  size_t fEntries; ///< Number of events to process for each column (i.e. number of rows).
91 
92  ////////////////////////////////////////////////////////////////////////////
93  /// Appends a cling::printValue call to the stringstream.
94  /// \tparam T the type of the event to convert
95  /// \param[in] stream Where the conversion function call will be chained.
96  /// \param[in] element The event to convert to its string representation
97  /// \param[in] index To which column the event belongs to
98  /// \return false, the event is not a collection
99  template <typename T, typename std::enable_if<!ROOT::TypeTraits::IsContainer<T>::value, int>::type = 0>
100  bool AddInterpreterString(std::stringstream &stream, T &element, const int &index)
101  {
102  stream << "*((std::string*)" << ROOT::Internal::RDF::PrettyPrintAddr(&(fRepresentations[index]))
103  << ") = cling::printValue((" << fTypes[index] << "*)" << ROOT::Internal::RDF::PrettyPrintAddr(&element) << ");";
104  return false;
105  }
106 
107  ////////////////////////////////////////////////////////////////////////////
108  /// Appends collection.size() cling::printValue call to the stringstream.
109  /// \tparam T the type of the event to convert
110  /// \param[in] stream Where the conversion function call will be chained.
111  /// \param[in] element The event to convert to its string representation
112  /// \param[in] index To which column the event belongs to
113  /// \return true, the event is a collection
114  /// This function chains a sequence of call to cling::printValue, one for each element of the collection.
115  template <typename T, typename std::enable_if<ROOT::TypeTraits::IsContainer<T>::value, int>::type = 0>
116  bool AddInterpreterString(std::stringstream &stream, T &collection, const int &index)
117  {
118  size_t collectionSize = std::distance(std::begin(collection), std::end(collection));
119  // Prepare the row to contain as many elements as the number of elements in the collection
120  fCollectionsRepresentations[index] = VecStr_t(collectionSize);
121 
122  // Use GetSplit to get the encapsulated type of the collection. For example, GetSplit on
123  // std::vector<std::vector<int>> will return std::vector<int>
124  VecStr_t output;
125  int nestedLoc = 0;
126  TClassEdit::GetSplit(fTypes[index].c_str(), output, nestedLoc);
127 
128  // For each element, append a call and feed the proper type returned by GetSplit
129  for (size_t i = 0; i < collectionSize; ++i) {
130  stream << "*((std::string*)" << ROOT::Internal::RDF::PrettyPrintAddr(&(fCollectionsRepresentations[index][i]))
131  << ") = cling::printValue((" << output[1] << "*)" << ROOT::Internal::RDF::PrettyPrintAddr(&(collection[i])) << ");";
132  }
133  return true;
134  }
135 
136  ////////////////////////////////////////////////////////////////////////////
137  /// Adds a single element to the next slot in the table
138  void AddToRow(const std::string &stringEle);
139 
140  ////////////////////////////////////////////////////////////////////////////
141  /// Adds a collection to the table
142  ///
143  /// Starting from the slot, the elements are added one under the other, each
144  /// one using a single cell of an entire row
145  void AddCollectionToRow(const VecStr_t &collection);
146 
147  ////////////////////////////////////////////////////////////////////////////
148  /// Moves to the next cell
149  ///
150  /// Moves to the next cell, and if the row is full moves to the next row.
151  void MovePosition();
152 
153  ////////////////////////////////////////////////////////////////////////////
154  /// Get the number of columns that do NOT fit in the characters limit
155  size_t GetNColumnsToShorten() const;
156 
157  ////////////////////////////////////////////////////////////////////////////
158  /// Adds a row of events to the table
159  template <typename... Columns>
160  void AddRow(Columns... columns)
161  {
162  std::stringstream calc; // JITted code
163  int columnIndex = 0;
164  // Unwrapping the parameters to create the JITted code.
165  fIsCollection = {AddInterpreterString(calc, columns, columnIndex++)...};
166 
167  // Let cling::printValue handle the conversion. This can be done only through cling-compiled code.
168  ROOT::Internal::RDF::InterpreterCalc(calc.str(), "Display");
169 
170  // Populate the fTable using the results of the JITted code.
171  for (size_t i = 0; i < fNColumns; ++i) {
172  if (fIsCollection[i]) {
173  AddCollectionToRow(fCollectionsRepresentations[i]);
174  } else {
175  AddToRow(fRepresentations[i]);
176  }
177  }
178  // This row has been parsed
179  fEntries--;
180  }
181 
182  ////////////////////////////////////////////////////////////////////////////
183  /// If the number of required rows has been parsed, returns false.
184  bool HasNext() { return fEntries > 0; }
185 
186  void EnsureCurrentColumnWidth(size_t w);
187 
188 public:
189  ////////////////////////////////////////////////////////////////////////////
190  /// Creates an RDisplay to print the event values
191  /// \param[in] columnNames Columns to print
192  /// \param[in] types The type of each column
193  /// \param[in] entries How many events per column (row) must be processed.
194  RDisplay(const VecStr_t &columnNames, const VecStr_t &types, int entries);
195 
196  ////////////////////////////////////////////////////////////////////////////
197  /// Prints the representation to the standard output
198  ///
199  /// Collections are shortened to the first and last element. The overall width
200  /// is shortened to a fixed size of TODO
201  void Print() const;
202 
203  ////////////////////////////////////////////////////////////////////////////
204  /// Returns the representation as a string
205  std::string AsString() const;
206 };
207 
208 } // namespace RDF
209 } // namespace ROOT
210 
211 #endif