Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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" // IsDataContainer, InterpreterCalc
15#include "ROOT/RVec.hxx"
16#include "ROOT/TypeTraits.hxx"
17#include "TClassEdit.h"
18
19#include <vector>
20#include <string>
21#include <sstream>
22#include <type_traits>
23
24namespace ROOT {
25namespace Internal {
26namespace RDF {
27
28template<typename T>
30std::string PrettyPrintAddr(const void *const addr);
31
33private:
35 std::string fRepresentation;
37
38public:
39 RDisplayElement(const std::string &representation);
41 void SetPrint();
42 void SetIgnore();
43 void SetDots();
44 bool IsPrint() const;
45 bool IsIgnore() const;
46 bool IsDot() const;
47 const std::string &GetRepresentation() const;
48 bool IsEmpty() const;
49};
50} // namespace RDF
51} // namespace Internal
52
53namespace RDF {
54
55/**
56 * \class ROOT::RDF::RDisplay
57 * \ingroup dataframe
58 * This class is the textual representation of the content of a columnar dataset.
59 *
60 * This class is provided to the user, and it can be used to print on screen
61 * the entries of the dataset requested through the Display action in a compact
62 * representation or to return the full representation of the events as a string.
63 * In order to apply proper formatting the content is buffered in memory as strings.
64 */
65class RDisplay {
66 template<typename T>
68
69public:
70 enum class EPrintFormat {
72 kHtml
73 };
74
77 };
78
79private:
80 using VecStr_t = std::vector<std::string>;
82 static constexpr char fgSeparator = ' '; ///< Spacing used to align the table entries
83 static constexpr unsigned fgMaxWidth = 100; ///< Maximum width of the table that Print() displays
84
85 VecStr_t fTypes; ///< This attribute stores the type of each column. It is needed by the interpreter to print it.
86 std::vector<bool> fIsCollection; ///< True if the column contains a collection. Collections are treated differently
87 ///< during the printing.
88 std::vector<std::vector<DElement_t>> fTable; ///< String representation of the data to be printed.
89 std::vector<unsigned short> fWidths; ///< Tracks the maximum width of each column, based on the largest element.
90
91 VecStr_t fRepresentations; ///< Used by the JITted code to store the string representation of the data.
92 std::vector<VecStr_t> fCollectionsRepresentations; ///< Used by the JITted code to store the string representation of
93 ///< the data in case of collection. Each row corresponds to a
94 ///< column, each column to a value of the collection.
95
96 size_t fNColumns; ///< Number of columns to be printed
97
98 size_t fCurrentRow = 0; ///< Row that is being filled
99 size_t fNextRow = 1; ///< Next row to be filled.
100 size_t fCurrentColumn = 0; ///< Column that is being filled.
101
102 size_t fNMaxCollectionElements = 10; // threshold on number of elements in collections to be Print()
103
104 ////////////////////////////////////////////////////////////////////////////
105 /// Appends a cling::printValue call to the stringstream
106 /// This overload works for non-collection data types which are also not
107 /// trivially representable as strings.
108 /// \tparam T the type of the event to convert
109 /// \param[in] stream Where the conversion function call will be chained.
110 /// \param[in] element The event to convert to its string representation
111 /// \param[in] index To which column the event belongs to
112 /// \return false, the event is not a collection
113 template <typename T,
114 std::enable_if_t<!std::is_arithmetic_v<T> && !ROOT::Internal::RDF::IsDataContainer<T>::value, int> = 0>
115 bool AddInterpreterString(std::stringstream &stream, T &element, const int &index)
116 {
117 stream << "*((std::string*)" << ROOT::Internal::RDF::PrettyPrintAddr(&(fRepresentations[index]))
118 << ") = cling::printValue((" << fTypes[index] << "*)" << ROOT::Internal::RDF::PrettyPrintAddr(&element)
119 << ");";
120 return false;
121 }
122
123 ////////////////////////////////////////////////////////////////////////////
124 /// Appends a string if the T type is an arithmetic type.
125 /// This overload works for arithmetic data types that are trivially
126 /// convertible to string.
127 /// \tparam T the type of the event to convert
128 /// \param[in] element The event to convert to its string representation
129 /// \param[in] index To which column the event belongs to
130 /// \return false, the event is not a collection
131 template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
132 bool AddInterpreterString(std::stringstream &, T &element, const int &index)
133 {
134 // Short-circuit the logic and just insert the string representation of
135 // the symple type at the right index.
136 fRepresentations[index] = std::to_string(element);
137 return false;
138 }
139
140 ////////////////////////////////////////////////////////////////////////////
141 /// Appends a string if the T type is boolean.
142 /// \param[in] element The event to convert to its string representation
143 /// \param[in] index To which column the event belongs to
144 /// \return false, the event is not a collection
145 bool AddInterpreterString(std::stringstream &, bool &element, const int &index)
146 {
147 // Short-circuit the logic and just insert the string representation of
148 // the boolean value at the right index.
149 fRepresentations[index] = (element ? "true" : "false");
150 return false;
151 }
152
153 ////////////////////////////////////////////////////////////////////////////
154 /// Appends collection.size() cling::printValue calls to the stringstream.
155 /// \tparam T the type of the event to convert
156 /// \param[in] stream Where the conversion function call will be chained.
157 /// \param[in] collection The event to convert to its string representation
158 /// \param[in] index To which column the event belongs to
159 /// \return true, the event is a collection
160 /// This function chains a sequence of call to cling::printValue, one for each element of the collection.
161 template <typename T, std::enable_if_t<ROOT::Internal::RDF::IsDataContainer<T>::value &&
162 !std::is_arithmetic_v<typename T::value_type>,
163 int> = 0>
164 bool AddInterpreterString(std::stringstream &stream, T &collection, const int &index)
165 {
166 size_t collectionSize = std::distance(std::begin(collection), std::end(collection));
167 // Prepare the row to contain as many elements as the number of elements in the collection
168 fCollectionsRepresentations[index] = VecStr_t(collectionSize);
169
170 // Use GetSplit to get the encapsulated type of the collection. For example, GetSplit on
171 // std::vector<std::vector<int>> will return std::vector<int>
173 int nestedLoc = 0;
174 TClassEdit::GetSplit(fTypes[index].c_str(), output, nestedLoc);
175
176 // For each element, append a call and feed the proper type returned by GetSplit
177 for (size_t i = 0; i < collectionSize; ++i) {
178 stream << "*((std::string*)" << ROOT::Internal::RDF::PrettyPrintAddr(&(fCollectionsRepresentations[index][i]))
179 << ") = cling::printValue((" << output[1] << "*)"
180 << ROOT::Internal::RDF::PrettyPrintAddr(&(collection[i])) << ");";
181 }
182 return true;
183 }
184
185 ////////////////////////////////////////////////////////////////////////////
186 /// Represent a collection of values as a collection of strings.
187 /// \tparam T the type of the event to convert. This must be a collection of
188 /// values of arithmetic type, but not boolean.
189 /// \param[in] collection The event to convert to its string representation
190 /// \param[in] index To which column the event belongs to
191 /// \return true, the event is a collection
192 template <typename T, std::enable_if_t<ROOT::Internal::RDF::IsDataContainer<T>::value &&
193 std::is_arithmetic_v<typename T::value_type> &&
194 !std::is_same_v<typename T::value_type, bool>,
195 int> = 0>
196 bool AddInterpreterString(std::stringstream &, T &collection, const int &index)
197 {
198 auto collectionSize = std::distance(std::begin(collection), std::end(collection));
199 VecStr_t collectionRepr(collectionSize);
200 std::generate(collectionRepr.begin(), collectionRepr.end(), [i = 0, &collection]() mutable {
201 auto valRepr = std::to_string(collection[i]);
202 i++;
203 return valRepr;
204 });
205 fCollectionsRepresentations[index] = std::move(collectionRepr);
206 return true;
207 }
208
209 ////////////////////////////////////////////////////////////////////////////
210 /// Represent a collection of booleans as a collection of strings.
211 /// \tparam T the type of the event to convert. This must be a collection of
212 /// boolean values.
213 /// \param[in] collection The event to convert to its string representation
214 /// \param[in] index To which column the event belongs to
215 /// \return true, the event is a collection
216 template <typename T, std::enable_if_t<ROOT::Internal::RDF::IsDataContainer<T>::value &&
217 std::is_same_v<typename T::value_type, bool>,
218 int> = 0>
219 bool AddInterpreterString(std::stringstream &, T &collection, const int &index)
220 {
221 auto collectionSize = std::distance(std::begin(collection), std::end(collection));
222 VecStr_t collectionRepr(collectionSize);
223 std::generate(collectionRepr.begin(), collectionRepr.end(), [i = 0, &collection]() mutable {
224 auto valRepr = (collection[i] ? "true" : "false");
225 i++;
226 return valRepr;
227 });
228 fCollectionsRepresentations[index] = std::move(collectionRepr);
229 return true;
230 }
231
232 ////////////////////////////////////////////////////////////////////////////
233 /// AddInterpreterString overload for arrays of chars.
234 ///
235 /// \param[in] charArr The character array to convert to string representation
236 /// \param[in] index To which column the event belongs
237 /// \return false, the event is not a collection
238 ///
239 /// This specialization for arrays of characters skips the cling::printValue
240 /// (i.e. appends nothing to the stream) and directly writes to fRepresentations the
241 /// string representation of the array of chars.
242 bool AddInterpreterString(std::stringstream &, ROOT::RVec<char> &charArr, const int &index)
243 {
244 // if null-terminated char array, do not copy the null terminator into std::string, it makes columns misaligned.
245 const auto length = charArr[charArr.size()-1] == '\0' ? charArr.size() - 1 : charArr.size();
246 const std::string arrAsStr(charArr.data(), length); // also works for non-null-terminated strings
247 fRepresentations[index] = arrAsStr;
248 return false; // do not treat this as a collection
249 }
250
251 ////////////////////////////////////////////////////////////////////////////
252 /// Adds a single element to the next slot in the table
253 void AddToRow(const std::string &stringEle);
254
255 ////////////////////////////////////////////////////////////////////////////
256 /// Adds a collection to the table
257 ///
258 /// Starting from the slot, the elements are added one under the other, each
259 /// one using a single cell of an entire row
260 void AddCollectionToRow(const VecStr_t &collection);
261
262 ////////////////////////////////////////////////////////////////////////////
263 /// Moves to the next cell
264 ///
265 /// Moves to the next cell, and if the row is full moves to the next row.
266 void MovePosition();
267
268 ////////////////////////////////////////////////////////////////////////////
269 /// Get the number of columns that do NOT fit in the characters limit
270 size_t GetNColumnsToShorten() const;
271
272 ////////////////////////////////////////////////////////////////////////////
273 /// Generate dashes between entries in Print() and AsString() Methods
274 std::string DashesBetweenLines(size_t lastColToPrint, bool allColumnsFit) const;
275
276 ////////////////////////////////////////////////////////////////////////////
277 /// Adds a row of events to the table
278 template <typename... Columns>
279 void AddRow(Columns &... columns)
280 {
281 std::stringstream calc; // JITted code
282 int columnIndex = 0;
283 // Unwrapping the parameters to create the JITted code.
284 fIsCollection = {AddInterpreterString(calc, columns, columnIndex++)...};
285
286 // Let cling::printValue handle the conversion. This can be done only through cling-compiled code.
287 const std::string toJit = calc.str();
288 if (!toJit.empty())
289 ROOT::Internal::RDF::InterpreterCalc(calc.str(), "Display");
290
291 // Populate the fTable using the results of the JITted code.
292 for (size_t i = 0; i < fNColumns; ++i) {
293 if (fIsCollection[i]) {
295 } else {
297 }
298 }
299 }
300
301 void EnsureCurrentColumnWidth(size_t w);
302
303 std::string AsStringInternal(bool considerDots, const RPrintOptions &options = {EPrintFormat::kMarkdown}) const;
304 std::string AsStringMarkdown(bool considerDots) const;
305 std::string AsStringHtml() const;
306
307public:
308 ////////////////////////////////////////////////////////////////////////////
309 /// Creates an RDisplay to print the event values
310 /// \param[in] columnNames Columns to print
311 /// \param[in] types The type of each column
312 /// \param[in] nMaxCollectionElements Number of maximum elements in collection.
313 RDisplay(const VecStr_t &columnNames, const VecStr_t &types, size_t nMaxCollectionElements);
314
315 ////////////////////////////////////////////////////////////////////////////
316 /// Prints the representation to the standard output
317 ///
318 /// Collections are shortened to the first and last element. The overall width
319 /// is shortened to a fixed number of columns that should fit the screen width.
320 void Print(const RPrintOptions &options = {EPrintFormat::kMarkdown}) const;
321
322 ////////////////////////////////////////////////////////////////////////////
323 /// Returns the representation as a string
324 std::string AsString(const RPrintOptions &options = {EPrintFormat::kMarkdown}) const;
325};
326
327} // namespace RDF
328} // namespace ROOT
329
330#endif
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h length
Helper class to let Display print compact tabular representations of the events.
Definition RDisplay.hxx:32
bool IsIgnore() const
Return if the cell has to be skipped.
bool IsDot() const
Return if the cell has to be replaced by "...".
const std::string & GetRepresentation() const
bool IsPrint() const
Return if the cell has to be printed.
void SetDots()
Flag this cell to be replaced by "...".
void SetPrint()
Flag this cell as to be printed.
void SetIgnore()
Flag this cell as to be skipped.
RDisplayElement()
Constructor assuming an empty representation to be printed.
pointer data() noexcept
Return a pointer to the vector's buffer, even if empty().
Definition RVec.hxx:280
This class is the textual representation of the content of a columnar dataset.
Definition RDisplay.hxx:65
void AddRow(Columns &... columns)
Adds a row of events to the table.
Definition RDisplay.hxx:279
void AddCollectionToRow(const VecStr_t &collection)
Adds a collection to the table.
size_t fCurrentColumn
Column that is being filled.
Definition RDisplay.hxx:100
bool AddInterpreterString(std::stringstream &, T &collection, const int &index)
Represent a collection of values as a collection of strings.
Definition RDisplay.hxx:196
size_t fNMaxCollectionElements
Definition RDisplay.hxx:102
std::vector< std::vector< DElement_t > > fTable
String representation of the data to be printed.
Definition RDisplay.hxx:88
std::vector< bool > fIsCollection
True if the column contains a collection.
Definition RDisplay.hxx:86
std::string AsStringHtml() const
void AddToRow(const std::string &stringEle)
Adds a single element to the next slot in the table.
size_t fCurrentRow
Row that is being filled.
Definition RDisplay.hxx:98
VecStr_t fRepresentations
Used by the JITted code to store the string representation of the data.
Definition RDisplay.hxx:91
std::string AsStringMarkdown(bool considerDots) const
void MovePosition()
Moves to the next cell.
std::vector< unsigned short > fWidths
Tracks the maximum width of each column, based on the largest element.
Definition RDisplay.hxx:89
bool AddInterpreterString(std::stringstream &stream, T &collection, const int &index)
Appends collection.size() cling::printValue calls to the stringstream.
Definition RDisplay.hxx:164
void Print(const RPrintOptions &options={EPrintFormat::kMarkdown}) const
Prints the representation to the standard output.
static constexpr unsigned fgMaxWidth
Maximum width of the table that Print() displays.
Definition RDisplay.hxx:83
std::string AsString(const RPrintOptions &options={EPrintFormat::kMarkdown}) const
Returns the representation as a string.
bool AddInterpreterString(std::stringstream &, bool &element, const int &index)
Appends a string if the T type is boolean.
Definition RDisplay.hxx:145
void EnsureCurrentColumnWidth(size_t w)
size_t fNextRow
Next row to be filled.
Definition RDisplay.hxx:99
bool AddInterpreterString(std::stringstream &, ROOT::RVec< char > &charArr, const int &index)
AddInterpreterString overload for arrays of chars.
Definition RDisplay.hxx:242
std::string DashesBetweenLines(size_t lastColToPrint, bool allColumnsFit) const
Generate dashes between entries in Print() and AsString() Methods.
std::string AsStringInternal(bool considerDots, const RPrintOptions &options={EPrintFormat::kMarkdown}) const
std::vector< std::string > VecStr_t
Definition RDisplay.hxx:80
std::vector< VecStr_t > fCollectionsRepresentations
Used by the JITted code to store the string representation of the data in case of collection.
Definition RDisplay.hxx:92
size_t GetNColumnsToShorten() const
Get the number of columns that do NOT fit in the characters limit.
static constexpr char fgSeparator
Spacing used to align the table entries.
Definition RDisplay.hxx:82
bool AddInterpreterString(std::stringstream &stream, T &element, const int &index)
Appends a cling::printValue call to the stringstream This overload works for non-collection data type...
Definition RDisplay.hxx:115
bool AddInterpreterString(std::stringstream &, T &element, const int &index)
Appends a string if the T type is an arithmetic type.
Definition RDisplay.hxx:132
VecStr_t fTypes
This attribute stores the type of each column. It is needed by the interpreter to print it.
Definition RDisplay.hxx:85
size_t fNColumns
Number of columns to be printed.
Definition RDisplay.hxx:96
A "std::vector"-like collection of values implementing handy operation to analyse them.
Definition RVec.hxx:1529
std::string PrettyPrintAddr(const void *const addr)
void InterpreterCalc(const std::string &code, const std::string &context="")
Jit code in the interpreter with TInterpreter::Calc, throw in case of errors.
Definition RDFUtils.cxx:345
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
int GetSplit(const char *type, std::vector< std::string > &output, int &nestedLoc, EModType mode=TClassEdit::kNone)
Stores in output (after emptying it) the split type.
Check for container traits.
Definition Utils.hxx:79
static void output()