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 : 5489 : explicit Print( const std::string& screen = {},
69 : : std::ostream& str = std::clog,
70 : : std::ios_base::openmode mode = std::ios_base::out,
71 : 5489 : std::ostream& qstr = std::cout ) :
72 : : m_null(),
73 [ + - ][ + - ]: 5489 : m_stream( str.rdbuf() == std::clog.rdbuf() ? m_null : str ),
[ + + ]
74 : : m_qstream( qstr ),
75 : : m_file( screen, mode ),
76 [ + - ][ + - ]: 5489 : m_tee(m_file.rdbuf(), screen.empty() ? m_file.rdbuf() : m_stream.rdbuf()),
[ + - ]
77 [ + - ][ + - ]: 21956 : 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 : 197 : 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 : 197 : std::streambuf* reset( std::streambuf* buf ) {
95 [ - + ]: 197 : if (stream<s>().rdbuf() == std::cout.rdbuf())
96 : 0 : m_qstream << "Warning: overwriting std::cout! Doing as requested...\n";
97 : 197 : 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 : 54894 : friend const Print& operator<<( const Print& os, const T& t )
107 : 54894 : { 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 : 1699 : friend const Print& operator<<( const Print& os,
134 : 1699 : 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 : 299 : void part( const std::string& t ) const {
140 : 299 : std::size_t half_length = t.size()/2;
141 [ + - ]: 598 : std::string left( half_length+1, '-' );
142 [ + + ][ + - ]: 598 : std::string right( (t.size()%2) ? (half_length+1) : half_length, '-' );
143 [ + - ][ + - ]: 598 : std::string underline( left + " o " + right );
144 [ + - ]: 598 : std::string upper( t );
145 : 299 : std::transform( begin(t), end(t), begin(upper), ::toupper );
146 [ + - ][ + - ]: 299 : upper = "< " + upper + " >";
147 [ + - ][ + - ]: 299 : stream<s>() << m_part_fmt % upper;
148 [ + - ][ + - ]: 299 : stream<s>() << m_part_underline_fmt % underline;
149 : 299 : }
150 : :
151 : : //! Formatted print of section header: t.
152 : : //! \param[in] t Section title to be printed
153 : : template< Style s = VERBOSE >
154 : 1065 : void section( const std::string& t ) const {
155 : 1065 : stream<s>() << m_section_title_fmt % m_section_indent % m_section_bullet
156 : 1065 : % t;
157 [ + - ]: 2130 : stream<s>() << m_section_underline_fmt % m_section_indent
158 [ + - ][ + - ]: 2130 : % std::string( m_section_indent.size() + 2 + t.size(), '-' );
[ + - ]
159 : 1065 : }
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 : 94 : void section( const std::string& name, const std::string& value ) const {
166 : 94 : stream<s>() << m_section_title_value_fmt % m_section_indent
167 : 94 : % m_section_bullet % name % value;
168 [ + - ]: 188 : stream<s>() << m_section_underline_fmt % m_section_indent
169 [ + - ][ + - ]: 282 : % std::string( m_section_indent.size() + 3 + name.size() +
[ + - ]
170 : 94 : value.size(), '-' );
171 : 94 : }
172 : :
173 : : //! Formatted print of subsection header: title.
174 : : //! \param[in] t Subsection title to be printed
175 : : template< Style s = VERBOSE >
176 : 118 : void subsection( const std::string& t ) const {
177 : 118 : stream<s>() << m_subsection_title_fmt % m_subsection_indent
178 : 118 : % m_subsection_bullet % t;
179 : 118 : }
180 : :
181 : : //! Formatted print of title.
182 : : //! \param[in] value Title string to be printed
183 : : template< Style s = VERBOSE >
184 : 99 : void title( const std::string& value ) const {
185 : : // clean up white spaces and format title with no indent or line-break
186 [ + - ][ + - ]: 396 : auto t = splitLines( value, "", "", 10000 );
[ + - ][ + - ]
187 : 99 : stream<s>() << m_section_title_value_fmt % m_section_indent
188 [ + - ][ + - ]: 99 : % m_section_bullet % "Title" % t;
[ + - ][ + - ]
[ + - ]
189 [ + - ]: 198 : stream<s>() << m_section_underline_fmt % m_section_indent
190 [ + - ][ + - ]: 198 : % std::string( m_section_indent.size()+8+t.size(), '-' );
[ + - ]
191 : 99 : }
192 : :
193 : : //! Formatted print of item: name.
194 : : //! \param[in] name Item name to be printed
195 : : template< Style s = VERBOSE >
196 : 99 : void item( const std::string& name ) const
197 : 99 : { 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 : 3598 : void item( const std::string& name, const T& value ) const
204 : 3598 : { 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 : : void longitem( const std::string& name, const T& value ) const
211 : : { 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 : : void item( const std::string& name, bool b ) const
223 : : { stream<s>() << m_item_name_value_fmt % m_item_indent % name %
224 : : 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 : 199 : void item( const std::string& name, const tk::Timer::Watch& watch ) const {
232 [ + - ]: 398 : stream<s>() << m_item_name_watch_fmt % m_item_indent % name
233 [ + - ][ + - ]: 398 : % watch.hrs.count() % watch.min.count() % watch.sec.count();
[ + - ][ + - ]
[ + - ]
234 : 199 : }
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 : 97 : void list( const std::string& name, const Container& entries ) const {
251 [ + - ]: 97 : if (!entries.empty()) {
252 : 97 : section<s>( name );
253 [ + + ]: 230 : for (auto& e : entries)
254 [ + - ][ + - ]: 133 : stream<s>() << m_list_item_fmt % m_item_indent % e;
[ + - ]
255 : : }
256 : 97 : }
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 : 5 : void list( const std::string& t, const Factory& factory ) const {
265 [ + - ]: 5 : if ( !factory.empty() ) {
266 [ + - ]: 5 : section<s>( t );
267 [ + - ]: 10 : Option option;
268 [ + + ]: 20 : for (const auto& f : factory)
269 [ + - ][ + - ]: 15 : stream<s>() << m_list_item_fmt % m_item_indent % option.name(f.first);
[ + - ][ + - ]
270 : : }
271 : 5 : }
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 : 100 : void time( const std::string& t,
283 : : const std::vector<
284 : : std::pair< std::string, ClockFormat > >& clock ) const
285 : : {
286 : 100 : section<s>( t );
287 [ + + ][ + - ]: 300 : for (const auto& c : clock) item<s>( c.first, c.second );
288 : 100 : }
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 : 96 : void note( const std::string& msg ) const
309 : 96 : { 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 : 93 : void diag( const std::string& msg ) const
315 : 93 : { 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 : : void diag( const std::vector< std::string >& labels,
324 : : const std::vector< std::string >& values,
325 : : bool precr = true ) const
326 : : {
327 : : Assert( labels.size() == values.size(), "Size mismatch" );
328 : : if (!labels.empty()) {
329 : : stream<s>() << (precr ? "\n" : "") <<
330 : : m_inprog_diag_fmt % labels[0] % values[0];
331 : : for (std::size_t i=1; i<labels.size(); ++i)
332 : : stream<s>() << m_inprog_extra_diag_fmt % labels[i] % values[i];
333 : : stream<s>() << (precr ? " " : "\n") << std::flush;
334 : : }
335 : : }
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 : : void diagstart( const std::string& msg ) const
342 : : { 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 : : void diagend( const std::string& msg ) const
348 : : { 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 : 0 : void charestate( const std::unordered_map< int,
354 : : std::vector< ChareState > >& state ) const
355 : : {
356 [ - - ][ - - ]: 0 : stream<s>() << m_charestate_frame_fmt %
357 : : "\n>>> =========== CHARE STATE ==========\n>>>";
358 : : // Group state by chare id
359 : 0 : std::map< int, std::vector< ChareState > > sorted_state;
360 [ - - ]: 0 : for (const auto& p : state)
361 [ - - ]: 0 : for (const auto& i : p.second)
362 [ - - ][ - - ]: 0 : sorted_state[ i.get< tag::id >() ].push_back( i );
363 : : // Sort states by time stamp
364 [ - - ]: 0 : for (auto& p : sorted_state)
365 [ - - ]: 0 : std::sort( begin(p.second), end(p.second),
366 : 0 : []( const ChareState& a, const ChareState& b )
367 : 0 : { return a.get< tag::time >() < b.get< tag::time >(); } );
368 : : // Output states
369 : 0 : std::size_t q = 0;
370 [ - - ]: 0 : for (const auto& p : sorted_state) {
371 [ - - ]: 0 : for (const auto& i : p.second) {
372 [ - - ]: 0 : stream<s>() << m_charestate_fmt % i.get< tag::ch >()
373 [ - - ]: 0 : % p.first
374 [ - - ]: 0 : % i.get< tag::fn >()
375 [ - - ]: 0 : % i.get< tag::pe >()
376 [ - - ]: 0 : % i.get< tag::it >()
377 [ - - ][ - - ]: 0 : % i.get< tag::time >();
378 : : }
379 [ - - ]: 0 : if (++q != sorted_state.size())
380 [ - - ][ - - ]: 0 : stream<s>() << m_charestate_frame_fmt % "";
381 : : }
382 [ - - ][ - - ]: 0 : stream<s>() << m_charestate_frame_fmt %
383 : : "\n>>> ======= END OF CHARE STATE =======\n>>>";
384 : 0 : }
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 : : 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 : : auto numdig = []( int i ) -> std::size_t {
414 : : return i > 0 ?
415 : : static_cast< std::size_t >( std::log10(static_cast<double>(i)) ) + 1
416 : : : 1; };
417 : : // Backspace so that new progress can overwrite old one
418 : : stream<s>() << std::string( progress_size, '\b' );
419 : : std::stringstream ss;
420 : : auto ip = prefix.cbegin();
421 : : auto id = done.cbegin();
422 : : auto im = max.cbegin();
423 : : progress_size = 0;
424 : : while (ip != prefix.cend()) {
425 : : // Compute new length of progress string
426 : : progress_size += 4 + ip->size() + numdig(*id) + numdig(*im);
427 : : // Construct and output new progress string to stream
428 : : ss << *ip << ":[" << *id << '/' << *im << ']';
429 : : ++ip; ++id; ++im;
430 : : // if next subprogress is not the last one, put in a comma
431 : : if (ip != prefix.cend()) {
432 : : ss << ", ";
433 : : progress_size += 2;
434 : : } else {
435 : : ss << ' ';
436 : : ++progress_size;
437 : : }
438 : : }
439 : : stream<s>() << m_progress_fmt % ss.str() << std::flush;
440 : : }
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 [ + - ][ + - ]: 40 : % std::string( ( alias ? pfx + *alias + ", " : "") +
[ + - ][ - - ]
[ + - ][ + - ]
[ - + ][ + - ]
[ - - ]
462 [ + - ][ + - ]: 30 : 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] copyright Copyright info to output
472 : : template< Style s = VERBOSE >
473 : 0 : void version( const std::string& executable,
474 : : const std::string& ver,
475 : : const std::string& copyright ) const
476 : 0 : { stream<s>() << m_version_fmt % executable % ver % copyright; }
477 : :
478 : : //! Print license information
479 : : //! \param[in] executable Name of executable to output license for
480 : : //! \param[in] lic License info to output
481 : : template< Style s = VERBOSE >
482 : : void license( const std::string& executable,
483 : : const std::string& lic ) const
484 : : { stream<s>() << m_license_fmt % executable % lic; }
485 : :
486 : : //! Print mandatory arguments information
487 : : //! \param[in] args Mandaatory-arguments infor to output
488 : : template< Style s = VERBOSE >
489 : 0 : void mandatory( const std::string& args ) const
490 : 0 : { stream<s>() << m_mandatory_fmt % args; }
491 : :
492 : : //! Print example usage information
493 : : //! \param[in] executable Name of executable to output usage info for
494 : : //! \param[in] example Example command line to output
495 : : //! \param[in] msg Message to output after example
496 : : template< Style s = VERBOSE >
497 : 0 : void usage( const std::string& executable,
498 : : const std::string& example,
499 : : const std::string& msg ) const
500 : 0 : { stream<s>() << m_usage_fmt % executable % example % msg; }
501 : :
502 : : //! Print lower and upper bounds for a keyword if defined
503 : : template< Style s = VERBOSE, typename Info >
504 : 1 : void bounds( const Info& info ) const {
505 [ - + ]: 1 : if (info.lower)
506 : 0 : stream<s>() << m_description_fmt
507 [ - - ][ - - ]: 0 : % splitLines( *info.lower, m_subsection_indent, "Lower bound: " );
[ - - ][ - - ]
[ - - ][ - - ]
508 [ - + ]: 1 : if (info.upper)
509 : 0 : stream<s>() << m_description_fmt
510 [ - - ][ - - ]: 0 : % splitLines( *info.upper, m_subsection_indent, "Upper bound: " );
[ - - ][ - - ]
[ - - ][ - - ]
511 : 1 : }
512 : :
513 : : //! \brief Formatted print of verbose help on a single command-line
514 : : //! parameter or control file keyword
515 : : //! \param[in] executable Name of executable to output help for
516 : : //! \param[in] kw Keyword help struct on which help is to be printed
517 : : template< Style s = VERBOSE, class HelpKw >
518 : 1 : void helpkw( const std::string& executable, const HelpKw& kw ) const {
519 [ - + ][ - - ]: 1 : Assert( !kw.keyword.empty(), "Empty keyword in Print::helpkw()" );
[ - - ][ - - ]
520 : 1 : const auto& info = kw.info;
521 : 1 : const auto& alias = info.alias;
522 : 1 : const auto& expt = info.expt;
523 : 1 : const auto& choices = info.choices;
524 : : // print keyword title
525 [ + - ]: 1 : if (kw.cmd)
526 : 1 : stream<s>() << m_helpkw_cmd_title_fmt
527 [ + - ]: 1 : % executable
528 [ + - ][ + - ]: 3 : % (alias ? "-" + *alias + ", " : "")
[ + - ][ - - ]
[ + - ][ - + ]
[ + - ][ - - ]
529 [ + - ][ + - ]: 2 : % kw.keyword;
530 : : else
531 : 0 : stream<s>() << m_helpkw_ctr_title_fmt
532 : 0 : % executable
533 : 0 : % kw.keyword;
534 : : // print short description
535 : 1 : stream<s>() << m_description_fmt
536 [ + - ][ + - ]: 1 : % splitLines( info.shortDescription, m_subsection_indent );
[ + - ][ + - ]
[ + - ][ + - ]
537 : : // print long description
538 : 1 : stream<s>() << m_description_fmt
539 [ + - ][ + - ]: 1 : % splitLines( info.longDescription, m_subsection_indent );
[ + - ][ + - ]
[ + - ][ + - ]
540 : : // print expected type description
541 [ - + ]: 1 : if (expt)
542 : 0 : stream<s>() << m_description_fmt
543 [ - - ][ - - ]: 0 : % splitLines( *expt, m_subsection_indent,
[ - - ][ - - ]
[ - - ][ - - ]
544 : : "Expected type: " );
545 : : // print lower bound if defined
546 : 1 : bounds< s >( info );
547 : : // print expected valied choices
548 [ - + ]: 1 : if (choices)
549 : 0 : stream<s>() << m_description_fmt
550 [ - - ][ - - ]: 0 : % splitLines( *choices, m_subsection_indent,
[ - - ][ - - ]
[ - - ][ - - ]
551 : : "Expected valid choices: ");
552 : 1 : }
553 : :
554 : : //! Print end of a part
555 : : template< Style s = VERBOSE >
556 : 298 : void endpart() const { stream<s>() << std::endl; }
557 : :
558 : : //! Print end of subsection
559 : : template< Style s = VERBOSE >
560 : 199 : void endsubsection() const { stream<s>() << '\n'; }
561 : :
562 : : //! Print raw data to stream.
563 : : //! \param[in] r Arbitrary data of arbitrary type as long as it defines
564 : : //! operator << for std::ostream.
565 : : template< Style s = VERBOSE, typename T >
566 : 2342 : void raw( const T& r ) const { stream<s>() << r; }
567 : :
568 : : //! Return verbose or quiet stream depending on style template argument.
569 : : //! Non-const version.
570 : : //! \return Reference to underlying std::ostream.
571 : : template< Style s = VERBOSE >
572 : 396 : std::ostream& stream() noexcept { return s ? m_stream : m_qstream; }
573 : :
574 : : //! Return verbose or quiet stream depending on style template argument.
575 : : //! Const version.
576 : : //! \return Reference to underlying std::ostream.
577 : : template< Style s = VERBOSE >
578 : 10616 : std::ostream& stream() const noexcept { return s ? m_stream : m_qstream; }
579 : :
580 : : //! Function object for echoing policies to screen
581 : : struct echoPolicies {
582 : : //! Need to store reference to host class whose data we operate on
583 : : const Print* const m_host;
584 : : //! Constructor: store host object pointer
585 : 186 : explicit echoPolicies( const Print* const host ) : m_host( host ) {}
586 : : //! Function call operator templated on the type that echos a policy
587 : 1581 : template< typename U > void operator()( brigand::type_<U> ) {
588 : : static_assert( tk::HasTypedef_code_v< typename U::info >,
589 : : "Policy code undefined for keyword" );
590 : : // Print policy code - policy name
591 [ + - ][ + - ]: 4743 : m_host->raw( m_host->m_item_indent + " " +
[ + - ]
592 [ + - ][ + - ]: 6324 : *U::code() + " - " + U::info::name() + '\n' );
[ + - ][ + - ]
593 : :
594 : 1581 : }
595 : : };
596 : :
597 : : //! Print RNGTest header. Text ASCII Art Generator used for executable
598 : : //! names: http://patorjk.com/software/taag.
599 : : template< Style s = VERBOSE >
600 : 5 : void headerRNGTest() const {
601 : 5 : stream<s>() << R"(
602 : : __ __ .__ __ __ __________ _______ ___________________ __
603 : : / \ / \_____ | | | | __ ___________ \ \ \______ \ \ \ / _____/\__ ___/___ _______/ |_
604 : : \ \/\/ /\__ \ | | | |/ // __ \_ __ \ \ \ | _/ / | \/ \ ___ | |_/ __ \ / ___/\ __\
605 : : \ / / __ \| |_| <\ ___/| | \/ / / | | \/ | \ \_\ \ | |\ ___/ \___ \ | |
606 : : \__/\ / (____ /____/__|_ \\___ >__| /_/ |____|_ /\____|__ /\______ / |____| \___ >____ > |__|
607 : : \/ \/ \/ \/ \/ \/ \/ \/ \/)"
608 : 5 : << std::endl;
609 : 5 : }
610 : :
611 : : //! Print UnitTest header. Text ASCII Art Generator used for executable
612 : : //! names: http://patorjk.com/software/taag.
613 : : template< Style s = VERBOSE >
614 : 2 : void headerUnitTest() const {
615 : 2 : stream<s>() << R"(
616 : : __ __ .__ __ __ ____ ___ .__ __ ___________ __
617 : : / \ / \_____ | | | | __ ___________ \ \ | | \____ |__|/ |\__ ___/___ _______/ |_
618 : : \ \/\/ /\__ \ | | | |/ // __ \_ __ \ \ \ | | / \| \ __\| |_/ __ \ / ___/\ __\
619 : : \ / / __ \| |_| <\ ___/| | \/ / / | | / | \ || | | |\ ___/ \___ \ | |
620 : : \__/\ / (____ /____/__|_ \\___ >__| /_/ |______/|___| /__||__| |____| \___ >____ > |__|
621 : : \/ \/ \/ \/ \/ \/ \/)"
622 : 2 : << std::endl;
623 : 2 : }
624 : :
625 : : //! Print Walker header. Text ASCII Art Generator used for executable names:
626 : : //! http://patorjk.com/software/taag.
627 : : template< Style s = VERBOSE >
628 : 94 : void headerWalker() const {
629 : 94 : stream<s>() << R"(
630 : : __ __ .__ __
631 : : / \ / \_____ | | | | __ ___________
632 : : \ \/\/ /\__ \ | | | |/ // __ \_ __ \
633 : : \ / / __ \| |_| <\ ___/| | \/
634 : : \__/\ / (____ /____/__|_ \\___ >__|
635 : : \/ \/ \/ \/)"
636 : 94 : << std::endl;
637 : 94 : }
638 : :
639 : : protected:
640 : : //! Bullets
641 : : const char m_section_bullet = '*';
642 : : const char m_subsection_bullet = '<';
643 : : //! Indents
644 [ + - ]: 5489 : const std::string m_section_indent = " ";
645 : : const std::string m_subsection_indent =
646 : : std::operator+(m_section_indent," ");
647 : : const std::string m_item_indent = std::operator+(m_subsection_indent," ");
648 : :
649 : : //! Format strings. See http://www.boost.org/doc/libs/release/libs/format.
650 : : using format = boost::format;
651 : : mutable format m_header_fmt = format("%|=80|\n");
652 : : mutable format m_part_fmt = format("\n%|=80|\n");
653 : : mutable format m_section_title_fmt = format("\n%s%c %s:\n");
654 : : mutable format m_section_title_value_fmt = format("\n%s%c %s: %s\n");
655 : : mutable format m_subsection_title_fmt = format("%s%c %s >\n");
656 : : mutable format m_list_item_fmt = format("%s%-40s\n");
657 : : mutable format m_note_fmt = format("%s%-40s\n");
658 : : mutable format m_diag_fmt = format("Walker> %s\n");
659 : : mutable format m_diag_start_fmt = format("Walker> %s ");
660 : : mutable format m_inprog_diag_fmt = format("Walker> %s: %s");
661 : : mutable format m_inprog_extra_diag_fmt = format(", %s: %s");
662 : : mutable format m_charestate_frame_fmt = format(">>> %s\n");
663 : : mutable format m_charestate_fmt =
664 : : format(">>> %s(%d)::%|-15| PE:%|-4| it:%|-5| t:%f\n");
665 : : mutable format m_diag_end_fmt = format("%s\n");
666 : : mutable format m_progress_fmt = format("%s");
667 : : mutable format m_help_title_fmt = format("\n%s %s\n");
668 : : mutable format m_help_item_fmt = format("%20s%11s %s\n");
669 : : mutable format m_helpkw_cmd_title_fmt =
670 : : format("\n%s command-line keyword %s--%s\n\n");
671 : : mutable format m_helpkw_ctr_title_fmt =
672 : : format("\n%s control file keyword '%s'\n\n");
673 : : mutable format m_helpkw_fmt = format("%s%s\n\n%s%s\n\n");
674 : : mutable format m_description_fmt = format("%s\n\n");
675 : : mutable format m_item_name_fmt = format("%s%-40s : ");
676 : : mutable format m_item_name_value_fmt = format("%s%-40s : %s\n");
677 : : mutable format m_item_longname_value_fmt = format("%s%-55s : %s\n");
678 : : mutable format m_item_name_watch_fmt = format("%s%-75s : %d:%d:%d\n");
679 : : mutable format m_item_name_perf_fmt = format("%s%-75s : %s\n");
680 : : mutable format m_item_widename_value_fmt = format("%s%-75s : %s\n");
681 : : mutable format m_part_underline_fmt = format(" %|=68|\n");
682 : : mutable format m_section_underline_fmt = format("%s%s\n");
683 : : mutable format m_version_fmt = format("\nWalker::%s, version %s\n%s\n\n");
684 : : mutable format m_license_fmt = format("\nWalker::%s\n\n%s\n\n");
685 : : mutable format m_mandatory_fmt = format("\n%s\n");
686 : : mutable format m_usage_fmt =
687 : : format("\n%s example usage:\n\n$ %s\n\n%s\n\n");
688 : :
689 : : // Stream objects
690 : : std::stringstream m_null; //!< Default verbose stream
691 : : std::ostream& m_stream; //!< Verbose stream
692 : : std::ostream& m_qstream; //!< Quiet stream
693 : :
694 : : private:
695 : : std::ofstream m_file; //!< File stream to save verbose stream in
696 : : tk::teebuf m_tee; //!< Used to tie m_stream and m_file
697 : : tk::scoped_streambuf_assignment m_ssa;
698 : : };
699 : :
700 : : } // tk::
701 : :
702 : : #endif // Print_h
|