|
|
|||
File indexing completed on 2025-12-16 10:29:49
0001 // Author: Enrico Guiraud, Danilo Piparo CERN, Massimo Tumolo Politecnico di Torino 08/2018 0002 0003 /************************************************************************* 0004 * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. * 0005 * All rights reserved. * 0006 * * 0007 * For the licensing terms see $ROOTSYS/LICENSE. * 0008 * For the list of contributors see $ROOTSYS/README/CREDITS. * 0009 *************************************************************************/ 0010 0011 #ifndef ROOT_RDFDISPLAYER 0012 #define ROOT_RDFDISPLAYER 0013 0014 #include "ROOT/RDF/Utils.hxx" // IsDataContainer, InterpreterCalc 0015 #include "ROOT/RVec.hxx" 0016 #include "ROOT/TypeTraits.hxx" 0017 #include "TClassEdit.h" 0018 0019 #include <vector> 0020 #include <string> 0021 #include <sstream> 0022 #include <type_traits> 0023 0024 namespace ROOT { 0025 namespace Internal { 0026 namespace RDF { 0027 0028 template<typename T> 0029 class DisplayHelper; 0030 std::string PrettyPrintAddr(const void *const addr); 0031 0032 class RDisplayElement { 0033 private: 0034 enum class PrintingAction { ToBePrinted, ToBeIgnored, ToBeDotted }; 0035 std::string fRepresentation; 0036 PrintingAction fPrintingAction; 0037 0038 public: 0039 RDisplayElement(const std::string &representation); 0040 RDisplayElement(); 0041 void SetPrint(); 0042 void SetIgnore(); 0043 void SetDots(); 0044 bool IsPrint() const; 0045 bool IsIgnore() const; 0046 bool IsDot() const; 0047 const std::string &GetRepresentation() const; 0048 bool IsEmpty() const; 0049 }; 0050 } // namespace RDF 0051 } // namespace Internal 0052 0053 namespace RDF { 0054 0055 /** 0056 * \class ROOT::RDF::RDisplay 0057 * \ingroup dataframe 0058 * This class is the textual representation of the content of a columnar dataset. 0059 * 0060 * This class is provided to the user, and it can be used to print on screen 0061 * the entries of the dataset requested through the Display action in a compact 0062 * representation or to return the full representation of the events as a string. 0063 * In order to apply proper formatting the content is buffered in memory as strings. 0064 */ 0065 class RDisplay { 0066 template<typename T> 0067 friend class ROOT::Internal::RDF::DisplayHelper; 0068 0069 public: 0070 enum class EPrintFormat { 0071 kMarkdown, 0072 kHtml 0073 }; 0074 0075 struct RPrintOptions { 0076 EPrintFormat fFormat; 0077 }; 0078 0079 private: 0080 using VecStr_t = std::vector<std::string>; 0081 using DElement_t = ROOT::Internal::RDF::RDisplayElement; 0082 static constexpr char fgSeparator = ' '; ///< Spacing used to align the table entries 0083 static constexpr unsigned fgMaxWidth = 100; ///< Maximum width of the table that Print() displays 0084 0085 VecStr_t fTypes; ///< This attribute stores the type of each column. It is needed by the interpreter to print it. 0086 std::vector<std::vector<DElement_t>> fTable; ///< String representation of the data to be printed. 0087 std::vector<unsigned short> fWidths; ///< Tracks the maximum width of each column, based on the largest element. 0088 0089 VecStr_t fRepresentations; ///< Used by the JITted code to store the string representation of the data. 0090 std::vector<VecStr_t> fCollectionsRepresentations; ///< Used by the JITted code to store the string representation of 0091 ///< the data in case of collection. Each row corresponds to a 0092 ///< column, each column to a value of the collection. 0093 0094 size_t fNColumns; ///< Number of columns to be printed 0095 0096 size_t fCurrentRow = 0; ///< Row that is being filled 0097 size_t fNextRow = 1; ///< Next row to be filled. 0098 size_t fCurrentColumn = 0; ///< Column that is being filled. 0099 0100 size_t fNMaxCollectionElements = 10; // threshold on number of elements in collections to be Print() 0101 0102 //////////////////////////////////////////////////////////////////////////// 0103 /// Appends a cling::printValue call to the stringstream 0104 /// This overload works for non-collection data types which are also not 0105 /// trivially representable as strings. 0106 /// \tparam T the type of the event to convert 0107 /// \param[in] stream Where the conversion function call will be chained. 0108 /// \param[in] element The event to convert to its string representation 0109 /// \param[in] index To which column the event belongs to 0110 /// \return false, the event is not a collection 0111 template <typename T, 0112 std::enable_if_t<!std::is_arithmetic_v<T> && !ROOT::Internal::RDF::IsDataContainer<T>::value, int> = 0> 0113 bool AddInterpreterString(std::stringstream &stream, T &element, const int &index) 0114 { 0115 stream << "*((std::string*)" << ROOT::Internal::RDF::PrettyPrintAddr(&(fRepresentations[index])) 0116 << ") = cling::printValue((" << fTypes[index] << "*)" << ROOT::Internal::RDF::PrettyPrintAddr(&element) 0117 << ");"; 0118 return false; 0119 } 0120 0121 //////////////////////////////////////////////////////////////////////////// 0122 /// Appends a string if the T type is an arithmetic type. 0123 /// This overload works for arithmetic data types that are trivially 0124 /// convertible to string. 0125 /// \tparam T the type of the event to convert 0126 /// \param[in] element The event to convert to its string representation 0127 /// \param[in] index To which column the event belongs to 0128 /// \return false, the event is not a collection 0129 template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0> 0130 bool AddInterpreterString(std::stringstream &, T &element, const int &index) 0131 { 0132 // Short-circuit the logic and just insert the string representation of 0133 // the symple type at the right index. 0134 fRepresentations[index] = std::to_string(element); 0135 return false; 0136 } 0137 0138 //////////////////////////////////////////////////////////////////////////// 0139 /// Appends a string if the T type is boolean. 0140 /// \param[in] element The event to convert to its string representation 0141 /// \param[in] index To which column the event belongs to 0142 /// \return false, the event is not a collection 0143 bool AddInterpreterString(std::stringstream &, bool &element, const int &index) 0144 { 0145 // Short-circuit the logic and just insert the string representation of 0146 // the boolean value at the right index. 0147 fRepresentations[index] = (element ? "true" : "false"); 0148 return false; 0149 } 0150 0151 //////////////////////////////////////////////////////////////////////////// 0152 /// Appends collection.size() cling::printValue calls to the stringstream. 0153 /// \tparam T the type of the event to convert 0154 /// \param[in] stream Where the conversion function call will be chained. 0155 /// \param[in] collection The event to convert to its string representation 0156 /// \param[in] index To which column the event belongs to 0157 /// \return true, the event is a collection 0158 /// This function chains a sequence of call to cling::printValue, one for each element of the collection. 0159 template <typename T, std::enable_if_t<ROOT::Internal::RDF::IsDataContainer<T>::value && 0160 !std::is_arithmetic_v<typename T::value_type>, 0161 int> = 0> 0162 bool AddInterpreterString(std::stringstream &stream, T &collection, const int &index) 0163 { 0164 size_t collectionSize = std::distance(std::begin(collection), std::end(collection)); 0165 // Prepare the row to contain as many elements as the number of elements in the collection 0166 fCollectionsRepresentations[index] = VecStr_t(collectionSize); 0167 0168 // Use GetSplit to get the encapsulated type of the collection. For example, GetSplit on 0169 // std::vector<std::vector<int>> will return std::vector<int> 0170 VecStr_t output; 0171 int nestedLoc = 0; 0172 TClassEdit::GetSplit(fTypes[index].c_str(), output, nestedLoc); 0173 0174 // For each element, append a call and feed the proper type returned by GetSplit 0175 for (size_t i = 0; i < collectionSize; ++i) { 0176 stream << "*((std::string*)" << ROOT::Internal::RDF::PrettyPrintAddr(&(fCollectionsRepresentations[index][i])) 0177 << ") = cling::printValue((" << output[1] << "*)" 0178 << ROOT::Internal::RDF::PrettyPrintAddr(&(collection[i])) << ");"; 0179 } 0180 return true; 0181 } 0182 0183 //////////////////////////////////////////////////////////////////////////// 0184 /// Represent a collection of values as a collection of strings. 0185 /// \tparam T the type of the event to convert. This must be a collection of 0186 /// values of arithmetic type, but not boolean. 0187 /// \param[in] collection The event to convert to its string representation 0188 /// \param[in] index To which column the event belongs to 0189 /// \return true, the event is a collection 0190 template <typename T, std::enable_if_t<ROOT::Internal::RDF::IsDataContainer<T>::value && 0191 std::is_arithmetic_v<typename T::value_type> && 0192 !std::is_same_v<typename T::value_type, bool>, 0193 int> = 0> 0194 bool AddInterpreterString(std::stringstream &, T &collection, const int &index) 0195 { 0196 auto collectionSize = std::distance(std::begin(collection), std::end(collection)); 0197 VecStr_t collectionRepr(collectionSize); 0198 std::generate(collectionRepr.begin(), collectionRepr.end(), [i = 0, &collection]() mutable { 0199 auto valRepr = std::to_string(collection[i]); 0200 i++; 0201 return valRepr; 0202 }); 0203 fCollectionsRepresentations[index] = std::move(collectionRepr); 0204 return true; 0205 } 0206 0207 //////////////////////////////////////////////////////////////////////////// 0208 /// Represent a collection of booleans as a collection of strings. 0209 /// \tparam T the type of the event to convert. This must be a collection of 0210 /// boolean values. 0211 /// \param[in] collection The event to convert to its string representation 0212 /// \param[in] index To which column the event belongs to 0213 /// \return true, the event is a collection 0214 template <typename T, std::enable_if_t<ROOT::Internal::RDF::IsDataContainer<T>::value && 0215 std::is_same_v<typename T::value_type, bool>, 0216 int> = 0> 0217 bool AddInterpreterString(std::stringstream &, T &collection, const int &index) 0218 { 0219 auto collectionSize = std::distance(std::begin(collection), std::end(collection)); 0220 VecStr_t collectionRepr(collectionSize); 0221 std::generate(collectionRepr.begin(), collectionRepr.end(), [i = 0, &collection]() mutable { 0222 auto valRepr = (collection[i] ? "true" : "false"); 0223 i++; 0224 return valRepr; 0225 }); 0226 fCollectionsRepresentations[index] = std::move(collectionRepr); 0227 return true; 0228 } 0229 0230 //////////////////////////////////////////////////////////////////////////// 0231 /// AddInterpreterString overload for arrays of chars. 0232 /// 0233 /// \param[in] charArr The character array to convert to string representation 0234 /// \param[in] index To which column the event belongs 0235 /// \return false, the event is not a collection 0236 /// 0237 /// This specialization for arrays of characters skips the cling::printValue 0238 /// (i.e. appends nothing to the stream) and directly writes to fRepresentations the 0239 /// string representation of the array of chars. 0240 bool AddInterpreterString(std::stringstream &, ROOT::RVec<char> &charArr, const int &index) 0241 { 0242 // if null-terminated char array, do not copy the null terminator into std::string, it makes columns misaligned. 0243 const auto length = charArr[charArr.size()-1] == '\0' ? charArr.size() - 1 : charArr.size(); 0244 const std::string arrAsStr(charArr.data(), length); // also works for non-null-terminated strings 0245 fRepresentations[index] = arrAsStr; 0246 return false; // do not treat this as a collection 0247 } 0248 0249 //////////////////////////////////////////////////////////////////////////// 0250 /// Adds a single element to the next slot in the table 0251 void AddToRow(const std::string &stringEle); 0252 0253 //////////////////////////////////////////////////////////////////////////// 0254 /// Adds a collection to the table 0255 /// 0256 /// Starting from the slot, the elements are added one under the other, each 0257 /// one using a single cell of an entire row 0258 void AddCollectionToRow(const VecStr_t &collection); 0259 0260 //////////////////////////////////////////////////////////////////////////// 0261 /// Moves to the next cell 0262 /// 0263 /// Moves to the next cell, and if the row is full moves to the next row. 0264 void MovePosition(); 0265 0266 //////////////////////////////////////////////////////////////////////////// 0267 /// Get the number of columns that do NOT fit in the characters limit 0268 size_t GetNColumnsToShorten() const; 0269 0270 //////////////////////////////////////////////////////////////////////////// 0271 /// Generate dashes between entries in Print() and AsString() Methods 0272 std::string DashesBetweenLines(size_t lastColToPrint, bool allColumnsFit) const; 0273 0274 //////////////////////////////////////////////////////////////////////////// 0275 /// Adds a row of events to the table 0276 template <typename... Columns> 0277 void AddRow(Columns &... columns) 0278 { 0279 std::stringstream calc; // JITted code 0280 int columnIndex = 0; 0281 // Unwrapping the parameters to create the JITted code. 0282 bool isCollection [] {AddInterpreterString(calc, columns, columnIndex++)...}; 0283 0284 // Let cling::printValue handle the conversion. This can be done only through cling-compiled code. 0285 const std::string toJit = calc.str(); 0286 if (!toJit.empty()) 0287 ROOT::Internal::RDF::InterpreterCalc(calc.str(), "Display"); 0288 0289 // Populate the fTable using the results of the JITted code. 0290 for (size_t i = 0; i < fNColumns; ++i) { 0291 if (isCollection[i]) { 0292 AddCollectionToRow(fCollectionsRepresentations[i]); 0293 } else { 0294 AddToRow(fRepresentations[i]); 0295 } 0296 } 0297 } 0298 0299 void EnsureCurrentColumnWidth(size_t w); 0300 0301 std::string AsStringInternal(bool considerDots, const RPrintOptions &options = {EPrintFormat::kMarkdown}) const; 0302 std::string AsStringMarkdown(bool considerDots) const; 0303 std::string AsStringHtml() const; 0304 0305 public: 0306 //////////////////////////////////////////////////////////////////////////// 0307 /// Creates an RDisplay to print the event values 0308 /// \param[in] columnNames Columns to print 0309 /// \param[in] types The type of each column 0310 /// \param[in] nMaxCollectionElements Number of maximum elements in collection. 0311 RDisplay(const VecStr_t &columnNames, const VecStr_t &types, size_t nMaxCollectionElements); 0312 0313 //////////////////////////////////////////////////////////////////////////// 0314 /// Prints the representation to the standard output 0315 /// 0316 /// Collections are shortened to the first and last element. The overall width 0317 /// is shortened to a fixed number of columns that should fit the screen width. 0318 void Print(const RPrintOptions &options = {EPrintFormat::kMarkdown}) const; 0319 0320 //////////////////////////////////////////////////////////////////////////// 0321 /// Returns the representation as a string 0322 std::string AsString(const RPrintOptions &options = {EPrintFormat::kMarkdown}) const; 0323 }; 0324 0325 } // namespace RDF 0326 } // namespace ROOT 0327 0328 #endif
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|