Branch data Line data Source code
1 : : // *****************************************************************************
2 : : /*!
3 : : \file src/Base/Print.hpp
4 : : \copyright 2012-2015 J. Bakosi,
5 : : 2016-2018 Los Alamos National Security, LLC.,
6 : : 2019-2021 Triad National Security, LLC.
7 : : All rights reserved. See the LICENSE file for details.
8 : : \brief General purpose pretty printer functionality
9 : : \details This file contains general purpose printer functions. Using the
10 : : functions defined here provides formatting, and a consistent look with
11 : : simple client-side code. For formatting, the Boost Format library is used,
12 : : see http://www.boost.org/doc/libs/release/libs/format.
13 : : */
14 : : // *****************************************************************************
15 : : #ifndef Print_h
16 : : #define Print_h
17 : :
18 : : #include <iostream>
19 : : #include <sstream>
20 : : #include <iomanip>
21 : : #include <cmath>
22 : : #include <array>
23 : : #include <vector>
24 : : #include <algorithm>
25 : : #include <unordered_map>
26 : :
27 : : #include "NoWarning/format.hpp"
28 : :
29 : : #include "Timer.hpp"
30 : : #include "Exception.hpp"
31 : : #include "Has.hpp"
32 : : #include "ChareState.hpp"
33 : : #include "PrintUtil.hpp"
34 : : #include "TeeBuf.hpp"
35 : :
36 : : namespace tk {
37 : :
38 : : //! Output verbosity. C-style enum as this is used for template argument.
39 : : enum Style { QUIET=0, VERBOSE=1 };
40 : :
41 : : //! Pretty printer base. Contains general purpose printer functions. Using the
42 : : //! functions defined here provides formatting, and a consistent look with
43 : : //! simple client-side code. For formatting, the Boost Format library is used,
44 : : //! see http://www.boost.org/doc/libs/release/libs.
45 : : class Print {
46 : :
47 : : public:
48 : : //! Constructor: Quiet output by default, only stuff written to qstr shown.
49 : : //! \details Instantiate with str = std::cout for verbose output. Any
50 : : // member function can be called by overriding the default stream via the
51 : : // template argument, Style, a C-style enum. Note: By default, str ==
52 : : // std::clog. This is used to initialize str to a local stringstream into
53 : : // which all verbose output goes by default, i.e., it will not be shown.
54 : : // This solution is chosen instead of trickery with null-streams, as
55 : : // boost:formatted output into null-streams caused invalid reads in
56 : : // valgrind. This way quiet output (formatted or not) simply goes into a
57 : : // local stringstream. In other words, the default argument to str,
58 : : // std::clog, is only used to detect whether client code passed a default
59 : : // argument or not: if it did not, the string stream is used for verbose
60 : : // output, if it did, the specified stream is used for the verbose output.
61 : : //! \param[in] screen Screen output filename. If an empty string is passed,
62 : : //! it is assumed that client code does not want to save the stream into
63 : : //! a file.
64 : : //! \param[in,out] str Verbose stream
65 : : //! \param[in] mode Open mode for screen output file, see
66 : : //! http://en.cppreference.com/w/cpp/io/ios_base/openmode
67 : : //! \param[in,out] qstr Quiet stream
68 : 8311 : explicit Print( const std::string& screen = {},
69 : : std::ostream& str = std::clog,
70 : : std::ios_base::openmode mode = std::ios_base::out,
71 : 8311 : std::ostream& qstr = std::cout ) :
72 : : m_null(),
73 [ + - ][ + - ]: 8311 : m_stream( str.rdbuf() == std::clog.rdbuf() ? m_null : str ),
[ + + ]
74 : : m_qstream( qstr ),
75 : : m_file( screen, mode ),
76 [ + - ][ + - ]: 8311 : m_tee(m_file.rdbuf(), screen.empty() ? m_file.rdbuf() : m_stream.rdbuf()),
[ + - ]
77 [ + - ][ + - ]: 24933 : m_ssa( screen.empty() ? m_file : m_stream, &m_tee ) {}
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + + ][ + - ]
[ + + ][ + - ]
78 : :
79 : : //! Save pointer to stream. This function, used in conjunction with reset(),
80 : : //! can be used to pass streams around. This is not possible in general,
81 : : //! since streams are not copyable. See this in action in, e.g.,
82 : : //! Control/Walker/CmdLine/Parser.C.
83 : : //! \return The internal stream buffer of the stream
84 : : template< Style s = VERBOSE >
85 : 210 : std::streambuf* save() const { return stream<s>().rdbuf(); }
86 : :
87 : : //! Reset stream to streambuf given. This function, used in conjunction with
88 : : //! save(), can be used to pass streams around. This is not possible in
89 : : //! general, since streams are not copyable. See this in action in, e.g.,
90 : : //! Control/Walker/CmdLine/Parser.C.
91 : : //! \param[in] buf Stream buffer of a stream
92 : : //! \return The internal stream buffer of the stream
93 : : template< Style s = VERBOSE >
94 : 210 : std::streambuf* reset( std::streambuf* buf ) {
95 [ - + ]: 210 : if (stream<s>().rdbuf() == std::cout.rdbuf())
96 : 0 : m_qstream << "Warning: overwriting std::cout! Doing as requested...\n";
97 : 210 : return stream<s>().rdbuf( buf );
98 : : }
99 : :
100 : : //! Operator << for printing any type to the verbose stream.
101 : : //! \param[in] os Reference to pretty printer object
102 : : //! \param[in] t Reference to an arbitrary object of type T. T must define
103 : : //! operator<< for std::ostream-compatible streams.
104 : : //! \return The internal stream buffer of the stream
105 : : template< typename T >
106 : 86172 : friend const Print& operator<<( const Print& os, const T& t )
107 : 86172 : { os.m_stream << t; return os; }
108 : :
109 : : //! Operator % for printing any type to the quiet stream.
110 : : //! \param[in] os Reference to pretty printer object
111 : : //! \param[in] t Reference to an arbitrary object of type T. T must define
112 : : //! operator<< for std::ostream-compatible streams.
113 : : //! \return The internal stream buffer of the stream
114 : : template< typename T >
115 : 3 : friend const Print& operator%( const Print& os, const T& t )
116 : 3 : { os.m_qstream << t; return os; }
117 : :
118 : : //! Operator % for a function pointer taking ostream returning ostream.
119 : : //! This is so that several of operators of % can be chained together.
120 : : //! \param[in] os Reference to pretty printer object
121 : : //! \param[in] pf Function pointer taking a reference to std::ostream and
122 : : //! returning a reference to std::ostream
123 : : //! \return Reference to pretty printer object
124 : 0 : friend const Print& operator%( const Print& os,
125 : 0 : std::ostream& (*pf)(std::ostream&) ) { os.m_qstream << pf; return os; }
126 : :
127 : : //! Operator << for a function pointer taking ostream returning ostream.
128 : : //! This is so that several of operators of << can be chained together.
129 : : //! \param[in] os Reference to pretty printer object
130 : : //! \param[in] pf Function pointer taking a reference to std::ostream and
131 : : //! returning a reference to std::ostream
132 : : //! \return Reference to pretty printer object
133 : 2214 : friend const Print& operator<<( const Print& os,
134 : 2214 : std::ostream& (*pf)(std::ostream&) ) { os.m_stream << pf; return os; }
135 : :
136 : : //! Formatted print of part header: title.
137 : : //! \param[in] t Part title to be printed
138 : : template< Style s = VERBOSE >
139 : 589 : void part( const std::string& t ) const {
140 : 589 : std::size_t half_length = t.size()/2;
141 [ + - ]: 1178 : std::string left( half_length+1, '-' );
142 [ + - ][ + - ]: 1178 : std::string right( (t.size()%2) ? (half_length+1) : half_length, '-' );
143 [ + - ][ + - ]: 1178 : std::string underline( left + " o " + right );
144 [ + - ]: 1178 : std::string upper( t );
145 : 589 : std::transform( begin(t), end(t), begin(upper), ::toupper );
146 [ + - ][ + - ]: 589 : upper = "< " + upper + " >";
147 [ + - ][ + - ]: 589 : stream<s>() << m_part_fmt % upper;
148 [ + - ][ + - ]: 589 : stream<s>() << m_part_underline_fmt % underline;
149 : 589 : }
150 : :
151 : : //! Formatted print of section header: t.
152 : : //! \param[in] t Section title to be printed
153 : : template< Style s = VERBOSE >
154 : 2773 : void section( const std::string& t ) const {
155 : 2773 : stream<s>() << m_section_title_fmt % m_section_indent % m_section_bullet
156 : 2773 : % t;
157 [ + - ]: 5546 : stream<s>() << m_section_underline_fmt % m_section_indent
158 [ + - ][ + - ]: 5546 : % std::string( m_section_indent.size() + 2 + t.size(), '-' );
[ + - ]
159 : 2773 : }
160 : :
161 : : //! Formatted print of section header: title : value.
162 : : //! \param[in] name Section title to be printed
163 : : //! \param[in] value Section value to be printed
164 : : template< Style s = VERBOSE >
165 : 190 : void section( const std::string& name, const std::string& value ) const {
166 : 190 : stream<s>() << m_section_title_value_fmt % m_section_indent
167 : 190 : % m_section_bullet % name % value;
168 [ + - ]: 380 : stream<s>() << m_section_underline_fmt % m_section_indent
169 [ + - ][ + - ]: 570 : % std::string( m_section_indent.size() + 3 + name.size() +
[ + - ]
170 : 190 : value.size(), '-' );
171 : 190 : }
172 : :
173 : : //! Formatted print of subsection header: title.
174 : : //! \param[in] t Subsection title to be printed
175 : : template< Style s = VERBOSE >
176 : 190 : void subsection( const std::string& t ) const {
177 : 190 : stream<s>() << m_subsection_title_fmt % m_subsection_indent
178 : 190 : % m_subsection_bullet % t;
179 : 190 : }
180 : :
181 : : //! Formatted print of title.
182 : : //! \param[in] value Title string to be printed
183 : : template< Style s = VERBOSE >
184 : 191 : void title( const std::string& value ) const {
185 : : // clean up white spaces and format title with no indent or line-break
186 [ + - ][ + - ]: 382 : auto t = splitLines( value, "", "", 10000 );
[ + - ][ + - ]
187 : 191 : stream<s>() << m_section_title_value_fmt % m_section_indent
188 [ + - ][ + - ]: 191 : % m_section_bullet % "Title" % t;
[ + - ][ + - ]
[ + - ]
189 [ + - ]: 382 : stream<s>() << m_section_underline_fmt % m_section_indent
190 [ + - ][ + - ]: 382 : % std::string( m_section_indent.size()+8+t.size(), '-' );
[ + - ]
191 : 191 : }
192 : :
193 : : //! Formatted print of item: name.
194 : : //! \param[in] name Item name to be printed
195 : : template< Style s = VERBOSE >
196 : 209 : void item( const std::string& name ) const
197 : 209 : { stream<s>() << m_item_name_fmt % m_item_indent % name; }
198 : :
199 : : //! Formatted print of item: name : value
200 : : //! \param[in] name Item name to be printed
201 : : //! \param[in] value Item value to be printed
202 : : template< Style s = VERBOSE, typename T >
203 : 10708 : void item( const std::string& name, const T& value ) const
204 : 10708 : { stream<s>() << m_item_name_value_fmt % m_item_indent % name % value; }
205 : :
206 : : //! Formatted print of item with wide name: name : value
207 : : //! \param[in] name Long item name to be printed
208 : : //! \param[in] value Item value to be printed
209 : : template< Style s = VERBOSE, typename T >
210 : 9 : void longitem( const std::string& name, const T& value ) const
211 : 9 : { stream<s>() << m_item_longname_value_fmt % m_item_indent % name % value; }
212 : :
213 : : //! Formatted print of item: name : bool
214 : : //! \param[in] name Item name to be printed
215 : : //! \param[in] b Item value as bool to be printed
216 : : //! \details boost::format does not directly support std::boolalpha, so it
217 : : //! must be done via boost::io::group, hence this overload for when the
218 : : //! item value to be printed is of type bool, which will print true/false
219 : : //! instead of 1/0.
220 : : //! \see https://stackoverflow.com/a/13709726
221 : : template< Style s = VERBOSE >
222 : 722 : void item( const std::string& name, bool b ) const
223 [ + - ][ + - ]: 1444 : { stream<s>() << m_item_name_value_fmt % m_item_indent % name %
[ + - ][ + - ]
224 : 1444 : boost::io::group(std::boolalpha, b); }
225 : :
226 : : //! Formatted print of item: h:m:s.
227 : : //! \param[in] name Item name to be printed
228 : : //! \param[in] watch Watch (in hours, minutes, seconds) to be printed as
229 : : //! item value
230 : : template< Style s = VERBOSE >
231 : 489 : void item( const std::string& name, const tk::Timer::Watch& watch ) const {
232 [ + - ]: 978 : stream<s>() << m_item_name_watch_fmt % m_item_indent % name
233 [ + - ][ + - ]: 978 : % watch.hrs.count() % watch.min.count() % watch.sec.count();
[ + - ][ + - ]
[ + - ]
234 : 489 : }
235 : :
236 : : //! Formatted print of a performance statistic (an item of a list)
237 : : //! \param[in] name Performance statistic name to be printed
238 : : //! \param[in] value Performance statistic value
239 : : template< Style s = VERBOSE >
240 : : void perfitem( const std::string& name, tk::real value ) const
241 : : { stream<s>() << m_item_name_perf_fmt % m_item_indent % name % value; }
242 : :
243 : : //! Formatted print of a list: name: entries...
244 : : //! \param[in] name Name of a section (consisting of a list) to be printed
245 : : //! \param[in] entries Container of type Container whose elements to be
246 : : //! printed. Container must be iterable, e.g., possible to be used in a
247 : : //! range-based for loop. \see
248 : : //! http://en.cppreference.com/w/cpp/language/range-for
249 : : template< Style s = VERBOSE, class Container >
250 : 193 : void list( const std::string& name, const Container& entries ) const {
251 [ + - ]: 193 : if (!entries.empty()) {
252 : 193 : section<s>( name );
253 [ + + ]: 423 : for (auto& e : entries)
254 [ + - ][ + - ]: 230 : stream<s>() << m_list_item_fmt % m_item_indent % e;
[ + - ]
255 : : }
256 : 193 : }
257 : :
258 : : //! Formatted print of a list: name: option names...
259 : : //! \param[in] t Title of the section containing a list
260 : : //! \param[in] factory Factory (an std::map) whose values are printed
261 : : //! interpreted as options (classes deriving from Toggle), defining the
262 : : //! name querying member function name().
263 : : template< class Option, Style s = VERBOSE, class Factory >
264 : : void list( const std::string& t, const Factory& factory ) const {
265 : : if ( !factory.empty() ) {
266 : : section<s>( t );
267 : : Option option;
268 : : for (const auto& f : factory)
269 : : stream<s>() << m_list_item_fmt % m_item_indent % option.name(f.first);
270 : : }
271 : : }
272 : :
273 : : //! Formatted print of elapsed times
274 : : //! \param[in] t Title of section containing a list of elapsed times
275 : : //! \param[in] clock std::vector of strings (clock names) and associated
276 : : //! timers which could be in various formats as long as there is a
277 : : //! corresponding item() overload that can apply operator << for outputing
278 : : //! their value to an output stream. Examples of allowed ClockFormats are:
279 : : //! tk::Timer::Watch, which is a struct containing a timestamp in h:m:s
280 : : //! format, and the return value of Timer::dsec(), which is a tk::real.
281 : : template< Style s = VERBOSE, class ClockFormat >
282 : 210 : void time( const std::string& t,
283 : : const std::vector<
284 : : std::pair< std::string, ClockFormat > >& clock ) const
285 : : {
286 : 210 : section<s>( t );
287 [ + + ][ + - ]: 700 : for (const auto& c : clock) item<s>( c.first, c.second );
288 : 210 : }
289 : :
290 : : //! Formatted print of performance statistics
291 : : //! \param[in] t Title of section containing a list of performance stats
292 : : //! \param[in] stat std::vector of strings (names of a performance
293 : : //! statistics) and associated values.
294 : : template< Style s = VERBOSE >
295 : : void perf( const std::string& t,
296 : : const std::vector< std::pair< std::string, tk::real > >& stat )
297 : : const
298 : : {
299 : : if (!stat.empty()) {
300 : : section<s>( t );
301 : : for (const auto& c : stat) perfitem<s>( c.first, c.second );
302 : : }
303 : : }
304 : :
305 : : //! Formatted print of a note
306 : : //! \param[in] msg Message to print as a note
307 : : template< Style s = VERBOSE >
308 : 2 : void note( const std::string& msg ) const
309 : 2 : { stream<s>() << m_note_fmt % m_item_indent % msg; }
310 : :
311 : : //! Echo formatted print of a diagnostics message
312 : : //! \param[in] msg Message to print as a diagnostics message
313 : : template< Style s = VERBOSE >
314 : 1145 : void diag( const std::string& msg ) const
315 : 1145 : { stream<s>() << m_diag_fmt % msg << std::flush; }
316 : :
317 : : //! Echo formatted print of a diagnostics message within a progress section
318 : : //! \param[in] labels Label parts of diagnostics message
319 : : //! \param[in] values Value parts of diagnostics message
320 : : //! \param[in] precr If true start with a CR/LF, if false end with it
321 : : //! \note The number of labels and values must equal.
322 : : template< Style s = VERBOSE >
323 : 87 : void diag( const std::vector< std::string >& labels,
324 : : const std::vector< std::string >& values,
325 : : bool precr = true ) const
326 : : {
327 [ - + ][ - - ]: 87 : Assert( labels.size() == values.size(), "Size mismatch" );
[ - - ][ - - ]
328 [ + - ]: 87 : if (!labels.empty()) {
329 [ + + ]: 87 : stream<s>() << (precr ? "\n" : "") <<
330 : 87 : m_inprog_diag_fmt % labels[0] % values[0];
331 [ + + ]: 492 : for (std::size_t i=1; i<labels.size(); ++i)
332 : 405 : stream<s>() << m_inprog_extra_diag_fmt % labels[i] % values[i];
333 [ + + ]: 87 : stream<s>() << (precr ? " " : "\n") << std::flush;
334 : : }
335 : 87 : }
336 : :
337 : : //! Start formatted print of a diagnostics message
338 : : //! Start formatted print of a diagnostics message
339 : : //! \param[in] msg First part of message to print as a diagnostics message
340 : : template< Style s = VERBOSE >
341 : 446 : void diagstart( const std::string& msg ) const
342 : 446 : { stream<s>() << m_diag_start_fmt % msg << std::flush; }
343 : :
344 : : //! Finish formatted print of a diagnostics message
345 : : //! \param[in] msg Last part of message to print as a diagnostics message
346 : : template< Style s = VERBOSE >
347 : 446 : void diagend( const std::string& msg ) const
348 : 446 : { stream<s>() << m_diag_end_fmt % msg << std::flush; }
349 : :
350 : : //! Print chare state collected
351 : : //! \param[in] state State map to print
352 : : template< Style s = VERBOSE >
353 : 1 : void charestate( const std::unordered_map< int,
354 : : std::vector< ChareState > >& state ) const
355 : : {
356 [ + - ][ + - ]: 1 : stream<s>() << m_charestate_frame_fmt %
357 : : "\n>>> =========== CHARE STATE ==========\n>>>";
358 : : // Group state by chare id
359 : 2 : std::map< int, std::vector< ChareState > > sorted_state;
360 [ + + ]: 5 : for (const auto& p : state)
361 [ + + ]: 1328 : for (const auto& i : p.second)
362 [ + - ][ + - ]: 1324 : sorted_state[ i.get< tag::id >() ].push_back( i );
363 : : // Sort states by time stamp
364 [ + + ]: 39 : for (auto& p : sorted_state)
365 [ + - ]: 38 : std::sort( begin(p.second), end(p.second),
366 : 5569 : []( const ChareState& a, const ChareState& b )
367 : 5569 : { return a.get< tag::time >() < b.get< tag::time >(); } );
368 : : // Output states
369 : 1 : std::size_t q = 0;
370 [ + + ]: 39 : for (const auto& p : sorted_state) {
371 [ + + ]: 1362 : for (const auto& i : p.second) {
372 [ + - ]: 2648 : stream<s>() << m_charestate_fmt % i.get< tag::ch >()
373 [ + - ]: 2648 : % p.first
374 [ + - ]: 2648 : % i.get< tag::fn >()
375 [ + - ]: 2648 : % i.get< tag::pe >()
376 [ + - ]: 2648 : % i.get< tag::it >()
377 [ + - ][ + - ]: 2648 : % i.get< tag::time >();
378 : : }
379 [ + + ]: 38 : if (++q != sorted_state.size())
380 [ + - ][ + - ]: 37 : stream<s>() << m_charestate_frame_fmt % "";
381 : : }
382 [ + - ][ + - ]: 1 : stream<s>() << m_charestate_frame_fmt %
383 : : "\n>>> ======= END OF CHARE STATE =======\n>>>";
384 : 1 : }
385 : :
386 : : //! Echo formatted print of a progress message
387 : : //! \param[in] prefix Strings to output prefixing the progress report
388 : : //! \param[in] done Array of integers indicating how many have been done
389 : : //! \param[in] max Array of integers indicating how many to be done
390 : : //! \param[in] progress_size Size of previous progress report (to overwrite)
391 : : //! \details All input arrays are the same size. The prefix strings
392 : : //! are optional, i.e., they can be empty strings. The function generates
393 : : //! an output to the stream configured in the following fashion:
394 : : //! pre1[done1/max1], pre2[done2/max2], ..., e.g., r:[1/3], b[2/8].
395 : : //! Whenever this function is called, a number of backspaces are put into
396 : : //! the stream so that the new progress report string overwrites the old
397 : : //! one. In order to backtrack the correct amount, the length of the old
398 : : //! progress report is stored (by whatever object holds us) and passed in
399 : : //! by reference in progress_size, which is overwritten here once it has
400 : : //! been used for backtracking. Therefore, for restarting a new series of
401 : : //! progress reports, this variable must be zeroed. Also, it is best to
402 : : //! not to interleave multiple tasks, because even if a different
403 : : //! progress_size is kept for each, there is no regard as to which line we
404 : : //! output to in the stream. In other words, multiple task outputs will
405 : : //! be intermingled, leading to confusing screen output.
406 : : template< std::size_t N, Style s = VERBOSE >
407 : 0 : void progress( const std::array< std::string, N >& prefix,
408 : : const std::array< int, N >& done,
409 : : const std::array< int, N >& max,
410 : : std::size_t& progress_size ) const
411 : : {
412 : : // lambda to determine the number of digits in an integer
413 : 0 : auto numdig = []( int i ) -> std::size_t {
414 : : return i > 0 ?
415 : 0 : static_cast< std::size_t >( std::log10(static_cast<double>(i)) ) + 1
416 [ - - ][ - - ]: 0 : : 1; };
417 : : // Backspace so that new progress can overwrite old one
418 [ - - ][ - - ]: 0 : stream<s>() << std::string( progress_size, '\b' );
419 [ - - ]: 0 : std::stringstream ss;
420 : 0 : auto ip = prefix.cbegin();
421 : 0 : auto id = done.cbegin();
422 : 0 : auto im = max.cbegin();
423 : 0 : progress_size = 0;
424 [ - - ]: 0 : while (ip != prefix.cend()) {
425 : : // Compute new length of progress string
426 : 0 : progress_size += 4 + ip->size() + numdig(*id) + numdig(*im);
427 : : // Construct and output new progress string to stream
428 [ - - ][ - - ]: 0 : ss << *ip << ":[" << *id << '/' << *im << ']';
[ - - ][ - - ]
[ - - ][ - - ]
429 : 0 : ++ip; ++id; ++im;
430 : : // if next subprogress is not the last one, put in a comma
431 [ - - ]: 0 : if (ip != prefix.cend()) {
432 [ - - ]: 0 : ss << ", ";
433 : 0 : progress_size += 2;
434 : : } else {
435 [ - - ]: 0 : ss << ' ';
436 : 0 : ++progress_size;
437 : : }
438 : : }
439 [ - - ][ - - ]: 0 : stream<s>() << m_progress_fmt % ss.str() << std::flush;
[ - - ][ - - ]
440 : 0 : }
441 : :
442 : : //! \brief Formatted print of help of one-liners on all command-line
443 : : //! parameters or control file keywords
444 : : //! \param[in] executable Name of executable to output help for
445 : : //! \param[in] pool std::map of keywords and their associated information
446 : : //! \param[in] msg Message to print after exectuable in the title
447 : : //! \param[in] pfx Prefix in front of alias, double prefix in front of
448 : : //! keyword
449 : : template< Style s = VERBOSE, class Help >
450 : 1 : void help( const std::string& executable,
451 : : const Help& pool,
452 : : const std::string& msg,
453 : : const std::string& pfx = "" ) const
454 : : {
455 : 1 : stream<s>() << m_help_title_fmt % executable % msg;
456 [ + + ]: 11 : for (const auto& keyword : pool) {
457 : 10 : const auto& info = keyword.second;
458 : 10 : const auto& alias = info.alias;
459 : 10 : const auto& expt = info.expt;
460 : 10 : stream<s>() << m_help_item_fmt
461 [ + - ][ + - ]: 20 : % std::string( ( alias ? pfx + *alias + ", " : "") +
[ + - ][ - - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ - + ][ + - ]
[ - - ][ - - ]
462 : 10 : pfx + pfx + keyword.first )
463 [ + + ][ + - ]: 30 : % (expt ? *expt : "")
[ + - ][ + - ]
[ + + ][ - - ]
464 [ + - ][ + - ]: 20 : % info.shortDescription;
465 : : }
466 : 1 : }
467 : :
468 : : //! Print version information
469 : : //! \param[in] executable Name of executable to output license for
470 : : //! \param[in] ver Version to output
471 : : //! \param[in] commit Commit to output
472 : : //! \param[in] copyright Copyright info to output
473 : : template< Style s = VERBOSE >
474 : 0 : void version( const std::string& executable,
475 : : const std::string& ver,
476 : : const std::string& commit,
477 : : const std::string& copyright ) const
478 : 0 : { stream<s>() << m_version_fmt % executable % ver % commit % copyright; }
479 : :
480 : : //! Print license information
481 : : //! \param[in] executable Name of executable to output license for
482 : : //! \param[in] lic License info to output
483 : : template< Style s = VERBOSE >
484 : 0 : void license( const std::string& executable,
485 : : const std::string& lic ) const
486 : 0 : { stream<s>() << m_license_fmt % executable % lic; }
487 : :
488 : : //! Print mandatory arguments information
489 : : //! \param[in] args Mandaatory-arguments infor to output
490 : : template< Style s = VERBOSE >
491 : 0 : void mandatory( const std::string& args ) const
492 : 0 : { stream<s>() << m_mandatory_fmt % args; }
493 : :
494 : : //! Print example usage information
495 : : //! \param[in] executable Name of executable to output usage info for
496 : : //! \param[in] example Example command line to output
497 : : //! \param[in] msg Message to output after example
498 : : template< Style s = VERBOSE >
499 : 0 : void usage( const std::string& executable,
500 : : const std::string& example,
501 : : const std::string& msg ) const
502 : 0 : { stream<s>() << m_usage_fmt % executable % example % msg; }
503 : :
504 : : //! Print lower and upper bounds for a keyword if defined
505 : : template< Style s = VERBOSE, typename Info >
506 : 1 : void bounds( const Info& info ) const {
507 [ - + ]: 1 : if (info.lower)
508 : 0 : stream<s>() << m_description_fmt
509 [ - - ][ - - ]: 0 : % splitLines( *info.lower, m_subsection_indent, "Lower bound: " );
[ - - ][ - - ]
[ - - ][ - - ]
510 [ - + ]: 1 : if (info.upper)
511 : 0 : stream<s>() << m_description_fmt
512 [ - - ][ - - ]: 0 : % splitLines( *info.upper, m_subsection_indent, "Upper bound: " );
[ - - ][ - - ]
[ - - ][ - - ]
513 : 1 : }
514 : :
515 : : //! \brief Formatted print of verbose help on a single command-line
516 : : //! parameter or control file keyword
517 : : //! \param[in] executable Name of executable to output help for
518 : : //! \param[in] kw Keyword help struct on which help is to be printed
519 : : template< Style s = VERBOSE, class HelpKw >
520 : 1 : void helpkw( const std::string& executable, const HelpKw& kw ) const {
521 [ - + ][ - - ]: 1 : Assert( !kw.keyword.empty(), "Empty keyword in Print::helpkw()" );
[ - - ][ - - ]
522 : 1 : const auto& info = kw.info;
523 : 1 : const auto& alias = info.alias;
524 : 1 : const auto& expt = info.expt;
525 : 1 : const auto& choices = info.choices;
526 : : // print keyword title
527 [ + - ]: 1 : if (kw.cmd)
528 : 1 : stream<s>() << m_helpkw_cmd_title_fmt
529 [ + - ]: 1 : % executable
530 [ + - ][ + - ]: 3 : % (alias ? "-" + *alias + ", " : "")
[ + - ][ - - ]
[ + - ][ - + ]
[ + - ][ - - ]
[ - - ]
531 [ + - ][ + - ]: 2 : % kw.keyword;
532 : : else
533 : 0 : stream<s>() << m_helpkw_ctr_title_fmt
534 : 0 : % executable
535 : 0 : % kw.keyword;
536 : : // print short description
537 : 1 : stream<s>() << m_description_fmt
538 [ + - ][ + - ]: 1 : % splitLines( info.shortDescription, m_subsection_indent );
[ + - ][ + - ]
[ + - ][ + - ]
539 : : // print long description
540 : 1 : stream<s>() << m_description_fmt
541 [ + - ][ + - ]: 1 : % splitLines( info.longDescription, m_subsection_indent );
[ + - ][ + - ]
[ + - ][ + - ]
542 : : // print expected type description
543 [ - + ]: 1 : if (expt)
544 : 0 : stream<s>() << m_description_fmt
545 [ - - ][ - - ]: 0 : % splitLines( *expt, m_subsection_indent,
[ - - ][ - - ]
[ - - ][ - - ]
546 : : "Expected type: " );
547 : : // print lower bound if defined
548 : 1 : bounds< s >( info );
549 : : // print expected valied choices
550 [ - + ]: 1 : if (choices)
551 : 0 : stream<s>() << m_description_fmt
552 [ - - ][ - - ]: 0 : % splitLines( *choices, m_subsection_indent,
[ - - ][ - - ]
[ - - ][ - - ]
553 : : "Expected valid choices: ");
554 : 1 : }
555 : :
556 : : //! Print end of a part
557 : : template< Style s = VERBOSE >
558 : 588 : void endpart() const { stream<s>() << std::endl; }
559 : :
560 : : //! Print end of subsection
561 : : template< Style s = VERBOSE >
562 : 415 : void endsubsection() const { stream<s>() << '\n'; }
563 : :
564 : : //! Print raw data to stream.
565 : : //! \param[in] r Arbitrary data of arbitrary type as long as it defines
566 : : //! operator << for std::ostream.
567 : : template< Style s = VERBOSE, typename T >
568 : 191 : void raw( const T& r ) const { stream<s>() << r; }
569 : :
570 : : //! Return verbose or quiet stream depending on style template argument.
571 : : //! Non-const version.
572 : : //! \return Reference to underlying std::ostream.
573 : : template< Style s = VERBOSE >
574 : 422 : std::ostream& stream() noexcept { return s ? m_stream : m_qstream; }
575 : :
576 : : //! Return verbose or quiet stream depending on style template argument.
577 : : //! Const version.
578 : : //! \return Reference to underlying std::ostream.
579 : : template< Style s = VERBOSE >
580 : 25653 : std::ostream& stream() const noexcept { return s ? m_stream : m_qstream; }
581 : :
582 : : //! Print Inciter header. Text ASCII Art Generator used for executable
583 : : //! names: http://patorjk.com/software/taag, Picture ASCII Art Generator
584 : : //! used for converting the logo text "Quinoa": http://picascii.com.
585 : : template< Style s = VERBOSE >
586 : 190 : void headerInciter() const {
587 : 190 : stream<s>() << R"(
588 : : ,::,` `.
589 : : .;;;'';;;: ;;#
590 : : ;;;@+ +;;; ;;;;;, ;;;;. ;;;;;, ;;;; ;;;; `;;;;;;: ;;;
591 : : :;;@` :;;' .;;;@, ,;@, ,;;;@: .;;;' .;+;. ;;;@#:';;; ;;;;'
592 : : ;;;# ;;;: ;;;' ;: ;;;' ;;;;; ;# ;;;@ ;;; ;+;;'
593 : : .;;+ ;;;# ;;;' ;: ;;;' ;#;;;` ;# ;;@ `;;+ .;#;;;.
594 : : ;;;# :;;' ;;;' ;: ;;;' ;# ;;; ;# ;;;@ ;;; ;# ;;;+
595 : : ;;;# .;;; ;;;' ;: ;;;' ;# ,;;; ;# ;;;# ;;;: ;@ ;;;
596 : : ;;;# .;;' ;;;' ;: ;;;' ;# ;;;; ;# ;;;' ;;;+ ;', ;;;@
597 : : ;;;+ ,;;+ ;;;' ;: ;;;' ;# ;;;' ;# ;;;' ;;;' ;':::;;;;
598 : : `;;; ;;;@ ;;;' ;: ;;;' ;# ;;;';# ;;;@ ;;;:,;+++++;;;'
599 : : ;;;; ;;;@ ;;;# .;. ;;;' ;# ;;;;# `;;+ ;;# ;# ;;;'
600 : : .;;; :;;@ ,;;+ ;+ ;;;' ;# ;;;# ;;; ;;;@ ;@ ;;;.
601 : : ';;; ;;;@, ;;;;``.;;@ ;;;' ;+ .;;# ;;; :;;@ ;;; ;;;+
602 : : :;;;;;;;+@` ';;;;;'@ ;;;;;, ;;;; ;;+ +;;;;;;#@ ;;;;. .;;;;;;
603 : : .;;#@' `#@@@: ;::::; ;:::: ;@ '@@@+ ;:::; ;::::::
604 : : :;;;;;;. .___ .__ __
605 : : .;@+@';;;;;;' | | ____ ____ |__|/ |_ ___________
606 : : ` '#''@` | |/ \_/ ___\| \ __\/ __ \_ __ \
607 : : | | | \ \___| || | \ ___/| | \/
608 : : |___|___| /\___ >__||__| \___ >__|
609 : : \/ \/ \/)"
610 : 190 : << std::endl;
611 : 190 : }
612 : :
613 : : //! Print UnitTest header. Text ASCII Art Generator used for executable
614 : : //! names: http://patorjk.com/software/taag, Picture ASCII Art Generator
615 : : //! used for converting the logo text "Quinoa": http://picascii.com.
616 : : template< Style s = VERBOSE >
617 : 2 : void headerUnitTest() const {
618 : 2 : stream<s>() << R"(
619 : : ,::,` `.
620 : : .;;;'';;;: ;;#
621 : : ;;;@+ +;;; ;;;;;, ;;;;. ;;;;;, ;;;; ;;;; `;;;;;;: ;;;
622 : : :;;@` :;;' .;;;@, ,;@, ,;;;@: .;;;' .;+;. ;;;@#:';;; ;;;;'
623 : : ;;;# ;;;: ;;;' ;: ;;;' ;;;;; ;# ;;;@ ;;; ;+;;'
624 : : .;;+ ;;;# ;;;' ;: ;;;' ;#;;;` ;# ;;@ `;;+ .;#;;;.
625 : : ;;;# :;;' ;;;' ;: ;;;' ;# ;;; ;# ;;;@ ;;; ;# ;;;+
626 : : ;;;# .;;; ;;;' ;: ;;;' ;# ,;;; ;# ;;;# ;;;: ;@ ;;;
627 : : ;;;# .;;' ;;;' ;: ;;;' ;# ;;;; ;# ;;;' ;;;+ ;', ;;;@
628 : : ;;;+ ,;;+ ;;;' ;: ;;;' ;# ;;;' ;# ;;;' ;;;' ;':::;;;;
629 : : `;;; ;;;@ ;;;' ;: ;;;' ;# ;;;';# ;;;@ ;;;:,;+++++;;;'
630 : : ;;;; ;;;@ ;;;# .;. ;;;' ;# ;;;;# `;;+ ;;# ;# ;;;'
631 : : .;;; :;;@ ,;;+ ;+ ;;;' ;# ;;;# ;;; ;;;@ ;@ ;;;.
632 : : ';;; ;;;@, ;;;;``.;;@ ;;;' ;+ .;;# ;;; :;;@ ;;; ;;;+
633 : : :;;;;;;;+@` ';;;;;'@ ;;;;;, ;;;; ;;+ +;;;;;;#@ ;;;;. .;;;;;;
634 : : .;;#@' `#@@@: ;::::; ;:::: ;@ '@@@+ ;:::; ;::::::
635 : : :;;;;;;. ____ ___ .__ __ ___________ __
636 : : .;@+@';;;;;;' | | \____ |__|/ |\__ ___/___ _______/ |_
637 : : ` '#''@` | | / \| \ __\| |_/ __ \ / ___/\ __\
638 : : | | / | \ || | | |\ ___/ \___ \ | |
639 : : |______/|___| /__||__| |____| \___ >____ > |__|
640 : : \/ \/ \/)"
641 : 2 : << std::endl;
642 : 2 : }
643 : :
644 : : //! Print MeshConv header. Text ASCII Art Generator used for executable
645 : : //! names: http://patorjk.com/software/taag, Picture ASCII Art Generator
646 : : //! used for converting the logo text "Quinoa": http://picascii.com.
647 : : template< Style s = VERBOSE >
648 : 19 : void headerMeshConv() const {
649 : 19 : stream<s>() << R"(
650 : : ,::,` `.
651 : : .;;;'';;;: ;;#
652 : : ;;;@+ +;;; ;;;;;, ;;;;. ;;;;;, ;;;; ;;;; `;;;;;;: ;;;
653 : : :;;@` :;;' .;;;@, ,;@, ,;;;@: .;;;' .;+;. ;;;@#:';;; ;;;;'
654 : : ;;;# ;;;: ;;;' ;: ;;;' ;;;;; ;# ;;;@ ;;; ;+;;'
655 : : .;;+ ;;;# ;;;' ;: ;;;' ;#;;;` ;# ;;@ `;;+ .;#;;;.
656 : : ;;;# :;;' ;;;' ;: ;;;' ;# ;;; ;# ;;;@ ;;; ;# ;;;+
657 : : ;;;# .;;; ;;;' ;: ;;;' ;# ,;;; ;# ;;;# ;;;: ;@ ;;;
658 : : ;;;# .;;' ;;;' ;: ;;;' ;# ;;;; ;# ;;;' ;;;+ ;', ;;;@
659 : : ;;;+ ,;;+ ;;;' ;: ;;;' ;# ;;;' ;# ;;;' ;;;' ;':::;;;;
660 : : `;;; ;;;@ ;;;' ;: ;;;' ;# ;;;';# ;;;@ ;;;:,;+++++;;;'
661 : : ;;;; ;;;@ ;;;# .;. ;;;' ;# ;;;;# `;;+ ;;# ;# ;;;'
662 : : .;;; :;;@ ,;;+ ;+ ;;;' ;# ;;;# ;;; ;;;@ ;@ ;;;.
663 : : ';;; ;;;@, ;;;;``.;;@ ;;;' ;+ .;;# ;;; :;;@ ;;; ;;;+
664 : : :;;;;;;;+@` ';;;;;'@ ;;;;;, ;;;; ;;+ +;;;;;;#@ ;;;;. .;;;;;;
665 : : .;;#@' `#@@@: ;::::; ;:::: ;@ '@@@+ ;:::; ;::::::
666 : : :;;;;;;. _____ .__ _________
667 : : .;@+@';;;;;;' / \ ____ _____| |__ \_ ___ \ ____ _______ __
668 : : ` '#''@` / \ / \_/ __ \ / ___| | \/ \ \/ / _ \ / \ \/ /
669 : : / Y \ ___/ \___ \| Y \ \___( <_> | | \ /
670 : : \____|__ /\___ /____ |___| /\______ /\____/|___| /\_/
671 : : \/ \/ \/ \/ \/ \/)"
672 : 19 : << std::endl;
673 : 19 : }
674 : :
675 : : protected:
676 : : //! Bullets
677 : : const char m_section_bullet = '*';
678 : : const char m_subsection_bullet = '<';
679 : : //! Indents
680 : : const std::string m_section_indent = " ";
681 : : const std::string m_subsection_indent =
682 : : std::operator+(m_section_indent," ");
683 : : const std::string m_item_indent = std::operator+(m_subsection_indent," ");
684 : :
685 : : //! Format strings. See http://www.boost.org/doc/libs/release/libs/format.
686 : : using format = boost::format;
687 : : mutable format m_header_fmt = format("%|=80|\n");
688 : : mutable format m_part_fmt = format("\n%|=80|\n");
689 : : mutable format m_section_title_fmt = format("\n%s%c %s:\n");
690 : : mutable format m_section_title_value_fmt = format("\n%s%c %s: %s\n");
691 : : mutable format m_subsection_title_fmt = format("%s%c %s >\n");
692 : : mutable format m_list_item_fmt = format("%s%-40s\n");
693 : : mutable format m_note_fmt = format("%s%-40s\n");
694 : : mutable format m_diag_fmt = format("Quinoa> %s\n");
695 : : mutable format m_diag_start_fmt = format("Quinoa> %s ");
696 : : mutable format m_inprog_diag_fmt = format("Quinoa> %s: %s");
697 : : mutable format m_inprog_extra_diag_fmt = format(", %s: %s");
698 : : mutable format m_charestate_frame_fmt = format(">>> %s\n");
699 : : mutable format m_charestate_fmt =
700 : : format(">>> %s(%d)::%|-15| PE:%|-4| it:%|-5| t:%f\n");
701 : : mutable format m_diag_end_fmt = format("%s\n");
702 : : mutable format m_progress_fmt = format("%s");
703 : : mutable format m_help_title_fmt = format("\n%s %s\n");
704 : : mutable format m_help_item_fmt = format("%25s%25s %s\n");
705 : : mutable format m_helpkw_cmd_title_fmt =
706 : : format("\n%s command-line keyword %s--%s\n\n");
707 : : mutable format m_helpkw_ctr_title_fmt =
708 : : format("\n%s control file keyword '%s'\n\n");
709 : : mutable format m_helpkw_fmt = format("%s%s\n\n%s%s\n\n");
710 : : mutable format m_description_fmt = format("%s\n\n");
711 : : mutable format m_item_name_fmt = format("%s%-40s : ");
712 : : mutable format m_item_name_value_fmt = format("%s%-40s : %s\n");
713 : : mutable format m_item_longname_value_fmt = format("%s%-55s : %s\n");
714 : : mutable format m_item_name_watch_fmt = format("%s%-75s : %d:%d:%d\n");
715 : : mutable format m_item_name_perf_fmt = format("%s%-75s : %s\n");
716 : : mutable format m_item_widename_value_fmt = format("%s%-75s : %s\n");
717 : : mutable format m_part_underline_fmt = format(" %|=68|\n");
718 : : mutable format m_section_underline_fmt = format("%s%s\n");
719 : : mutable format m_version_fmt =
720 : : format("\nQuinoa::%s, version %s (SHA1: %s)\n%s\n\n");
721 : : mutable format m_license_fmt = format("\nQuinoa::%s\n\n%s\n\n");
722 : : mutable format m_mandatory_fmt = format("\n%s\n");
723 : : mutable format m_usage_fmt =
724 : : format("\n%s example usage:\n\n$ %s\n\n%s\n\n");
725 : :
726 : : // Stream objects
727 : : std::stringstream m_null; //!< Default verbose stream
728 : : std::ostream& m_stream; //!< Verbose stream
729 : : std::ostream& m_qstream; //!< Quiet stream
730 : :
731 : : private:
732 : : std::ofstream m_file; //!< File stream to save verbose stream in
733 : : tk::teebuf m_tee; //!< Used to tie m_stream and m_file
734 : : tk::scoped_streambuf_assignment m_ssa;
735 : : };
736 : :
737 : : } // tk::
738 : :
739 : : #endif // Print_h
|