Tomographer  v4.0
Tomographer C++ Framework Documentation
fmt.h
Go to the documentation of this file.
1 /* This file is part of the Tomographer project, which is distributed under the
2  * terms of the MIT license.
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2016 ETH Zurich, Institute for Theoretical Physics, Philippe Faist
7  * Copyright (c) 2017 Caltech, Institute for Quantum Information and Matter, Philippe Faist
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a copy
10  * of this software and associated documentation files (the "Software"), to deal
11  * in the Software without restriction, including without limitation the rights
12  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13  * copies of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included in
17  * all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27 
28 #ifndef TOMOGRAPHER_TOOLS_FMT_H
29 #define TOMOGRAPHER_TOOLS_FMT_H
30 
37 #include <cstdio>
38 #include <cstdarg>
39 
40 #include <chrono>
41 #include <string>
42 #include <sstream> // stringstream
43 #include <iostream>
44 #include <utility> // std::declval
45 
46 #include <tomographer/tools/cxxutil.h> // PRINTFN_ARGS_SAFE
47 
48 
49 namespace Tomographer {
50 namespace Tools {
51 
52 
53 //
54 // =============================================================================
55 //
56 // Formatting Utilities
57 //
58 
59 
65 TOMOGRAPHER_EXPORT class BadFmtsFormat : public std::exception
66 {
67  std::string msg;
68 public:
70  BadFmtsFormat(const std::string& msg_) : msg(msg_) { }
71  ~BadFmtsFormat() throw() { }
72 
73  const char * what() const throw() {
74  return msg.c_str();
75  }
76 };
77 
78 
79 
84 inline std::string vfmts(const char* fmt, va_list vl)
85 {
86  // check out printf() formatting for std::string:
87  // http://stackoverflow.com/a/10150393/1694896
88  // http://stackoverflow.com/a/26197300/1694896
89 
90  // on MinGW, can't find std::vsnprintf() because for some reason it's declared in the
91  // global scope... so just import std namespace here and use generic vsnprintf() call.
92  using namespace std;
93 
94  int size = 10;
95  char * buffer = new char[size];
96  va_list ap1;
97  va_copy(ap1, vl);
98  int nsize = vsnprintf(buffer, size, fmt, ap1);
99  if (nsize < 0) {
100  // failure: bad format probably
101  throw BadFmtsFormat("vsnprintf("+std::string(fmt)+") failure: code="+std::to_string(nsize));
102  }
103  if(size <= nsize) {
104  // buffer too small: delete buffer and try again
105  delete[] buffer;
106  size = nsize+1; // +1 for "\0"
107  buffer = new char[size];
108  nsize = vsnprintf(buffer, size, fmt, vl);
109  }
110  std::string ret(buffer);
111  delete[] buffer;
112  va_end(ap1);
113  return ret;
114 }
115 
116 
121 inline std::string fmts(const char * fmt, ...) PRINTF1_ARGS_SAFE;
122 
123 // definition. It seems definitions cannot have function attributes (here
124 // PRINTF1_ARGS_SAFE), so that's why it's separate
125 inline std::string fmts(const char * fmt, ...)
126 {
127  va_list ap;
128  va_start(ap, fmt);
129  std::string result = vfmts(fmt, ap);
130  va_end(ap);
131  return result;
132 }
133 
134 
146 #define streamstr(tokens) \
147  dynamic_cast<std::ostringstream&>( \
148  std::ostringstream().seekp(0) << tokens \
149  ).str() \
150 
151 
158 #define streamcstr(tokens) streamstr(tokens).c_str()
159 
160 
161 
162 //
163 // utility to stream an object, if possible
164 //
165 
166 namespace tomo_internal {
167 // see http://stackoverflow.com/a/9154394/1694896
168 // see sfinae_yes and sfinae_no in cxxutil.h
169 template<typename T> static auto test_has_stream_op(int)
170  -> typename sfinae_yes<decltype(*((std::ostream*)(NULL)) << *((T*)(NULL)))>::yes&;
171 template<typename T> static auto test_has_stream_op(long)
172  -> typename sfinae_no<>::no&;
173 // template<typename T, int dummy_value,
174 // typename EnabledIfType = decltype(std::declval<std::ostream&>() << std::declval<T>())>
175 // struct test_has_stream_op { static constexpr bool value = true; };
176 // template<typename T, long dummy_value>
177 // struct test_has_stream_op<T,dummy_value,void> { static constexpr bool value = false; };
178 // template<typename T>
179 // struct has_stream_op {
180 // static constexpr bool value = test_has_stream_op<T, 0>::value;
181 // };
182 } // namespace tomo_internal
183 
184 
195 template<typename T>
196 struct hasOStreamOp {
197  static constexpr bool value = (sizeof(tomo_internal::test_has_stream_op<T>(0))
198  == sizeof(typename tomo_internal::sfinae_yes<>::yes));
199 };
200 
201 
202 namespace tomo_internal {
204 template<typename T_>
205 struct StreamIfPossibleWrapper
206 {
208  typedef T_ T;
212  StreamIfPossibleWrapper(
213  const T& obj_,
214  std::string before_,
215  std::string after_,
216  std::string alternative_
217  )
218  : obj(obj_), before(before_), after(after_), alternative(alternative_)
219  {
220  }
221 
223  const T & obj;
224 
226  const std::string before;
228  const std::string after;
230  const std::string alternative;
231 
232  // internal :
233 
236  void stream_into(OStream&& stream) const
237  {
238  stream << alternative;
239  }
242  void stream_into(OStream&& stream) const
243  {
244  stream << before << obj << after;
245  }
246 };
248 template<typename T>
249 std::ostream & operator<<(std::ostream & stream, const StreamIfPossibleWrapper<T>& wobj)
250 {
251  wobj.stream_into(stream);
252  return stream;
253 }
255 template<typename T>
256 std::ostream&& operator<<(std::ostream&& stream, const StreamIfPossibleWrapper<T>& wobj)
257 {
258  wobj.stream_into(stream);
259  return std::move(stream);
260 }
261 }
262 
263 
264 
265 #ifndef TOMOGRAPHER_PARSED_BY_DOXYGEN
267 inline std::string streamIfPossible(const T& /*obj*/)
268 {
269  // obj is not streamable
270  return std::string("<")+typeid(T).name()+std::string(">");
271 }
273 inline const T& streamIfPossible(const T& obj)
274 {
275  return obj;
276 }
277 template<typename T>
278 inline tomo_internal::StreamIfPossibleWrapper<T>
279 streamIfPossible(const T& obj, std::string before,
280  std::string after = std::string(),
281  std::string alternative = "<"+std::string(typeid(T).name())+">")
282 {
283  return tomo_internal::StreamIfPossibleWrapper<T>(obj, std::move(before),
284  std::move(after), std::move(alternative));
285 }
286 #else
287 
307 template<typename T>
308 inline _Unspecified streamIfPossible(const T& obj)
309 {
310 }
342 template<typename T>
343 inline _Unspecified streamIfPossible(const T& obj,
344  std::string before,
345  std::string after = std::string(),
346  std::string alternative = "<"+std::string(typeid(T).name())+">")
347 {
348 }
349 #endif
350 
351 
352 
353 
354 
355 
356 
357 // =============================================================================
358 
359 
367 inline std::string fmtDuration(double seconds)
368 {
369  // split `seconds' into integral part and fractional part
370  double dt_i_d;
371  double dt_f = std::modf(seconds, &dt_i_d);
372  int dt_i = (int)(dt_i_d+0.5);
373 
374  return fmts("%d:%02d:%02d.%03d", dt_i/3600, (dt_i/60)%60, dt_i%60, (int)(dt_f*1000+0.5));
375 };
376 
386 template<typename Rep, typename Period>
388 {
389  typedef std::chrono::duration<Rep, Period> Duration;
390 
391  // delta-time, in seconds and fraction of seconds
392  double seconds = (double)dt.count() * Duration::period::num / Duration::period::den ;
393 
394  return fmtDuration(seconds);
395 };
396 
397 
398 
399 
400 
404 TOMOGRAPHER_EXPORT class ConsoleFormatterHelper
405 {
406 public:
414  ConsoleFormatterHelper(int width = 0)
415  : _columns(Tomographer::Tools::getWidthForTerminalOutput(width))
416  {
417  }
418 
420  inline int columns() const { return _columns; }
421 
429  {
430  if ((int)x.size() > columns()) {
431  return std::move(x) + "\n";
432  }
433  const int r = columns() - (int)x.size();
434  const int rleft = r/2;
435  const int rright = r - rleft; // may differ from r/2 if r is odd
436  return std::string(rleft, ' ') + std::move(x) + std::string(rright, ' ') + "\n";
437  }
438 
446  {
447  if ((int)x.size() > columns()) {
448  return std::move(x) + "\n";
449  }
450  const int r = columns() - (int)x.size();
451  return std::string(r, ' ') + std::move(x) + "\n";
452  }
453 
461  {
462  if ((int)x.size() > columns()) {
463  return std::move(x) + "\n";
464  }
465  const int r = columns() - (int)x.size();
466  return std::move(x) + std::string(r, ' ') + "\n";
467  }
468 
469  inline std::string hrule(char pattern = '-')
470  {
471  // remember that std::string(10, '-') constructs 10 copies of '-', that is : "----------".
472  return std::string(columns(), pattern) + std::string("\n");
473  }
474 
475 private:
476  const int _columns;
477 };
478 
479 
480 } // namespace Tools
481 } // namespace Tomographer
482 
483 
484 #endif
std::string centerLine(std::string x)
Produce a centered string.
Definition: fmt.h:428
Base namespace for the Tomographer project.
Definition: densellh.h:45
std::string vfmts(const char *fmt, va_list vl)
printf- formatting to a std::string, with va_list pointer
Definition: fmt.h:84
BadFmtsFormat(const std::string &msg_)
Construct an exception for bad printf formatting. Provide an error message here.
Definition: fmt.h:70
T to_string(T... args)
STL namespace.
std::string fmtDuration(double seconds)
Format a number of seconds into a human-readable string.
Definition: fmt.h:367
T modf(T... args)
Exception for bad printf format.
Definition: fmt.h:65
std::string leftLine(std::string x)
Produce a left-aligned string.
Definition: fmt.h:460
STL class.
Minimal tool for formatting console stuff with fixed line width.
Definition: fmt.h:404
_Unspecified streamIfPossible(const T &obj)
Utility to stream an object, but only if "<<" overload exists.
Definition: fmt.h:308
Some C++ utilities, with a tad of C++11 tricks.
STL class.
T move(T... args)
T vsnprintf(T... args)
T size(T... args)
std::string rightLine(std::string x)
Produce a right-aligned string.
Definition: fmt.h:445
std::string fmts(const char *fmt,...)
printf- format to a std::string
Definition: fmt.h:125
ConsoleFormatterHelper(int width=0)
Constructor.
Definition: fmt.h:414
Traits class to see whether an object exposes a "<<" operator overload for std::ostream.
Definition: fmt.h:196
VarValueDecoder< T >::RetType value(const Var &var)
Access the value of the given variable, as a C++ type.
Definition: ezmatio.h:878
int getWidthForTerminalOutput(int max_width=0)
Return a suitable width for displaying stuff on the standard output.
Definition: cxxutil.h:434
STL class.
int columns() const
The number of character columns (as specified to the constructor)
Definition: fmt.h:420