Tomographer  v2.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) 2015 ETH Zurich, Institute for Theoretical Physics, Philippe Faist
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  */
26 
27 #ifndef TOMOGRAPHER_TOOLS_FMT_H
28 #define TOMOGRAPHER_TOOLS_FMT_H
29 
36 #include <cstdio>
37 #include <cstdarg>
38 
39 #include <chrono>
40 #include <string>
41 #include <sstream> // stringstream
42 #include <iostream>
43 #include <utility> // std::declval
44 
45 #include <tomographer2/tools/cxxutil.h> // PRINTFN_ARGS_SAFE
46 
47 
48 namespace Tomographer {
49 namespace Tools {
50 
51 
52 //
53 // =============================================================================
54 //
55 // Formatting Utilities
56 //
57 
58 
65 {
66  std::string msg;
67 public:
69  BadFmtsFormat(const std::string& msg_) : msg(msg_) { }
70  ~BadFmtsFormat() throw() { }
71 
72  const char * what() const throw() {
73  return msg.c_str();
74  }
75 };
76 
77 
78 
83 inline std::string vfmts(const char* fmt, va_list vl)
84 {
85  // check out printf() formatting for std::string:
86  // http://stackoverflow.com/a/10150393/1694896
87  // http://stackoverflow.com/a/26197300/1694896
88 
89  // on MinGW, can't find std::vsnprintf() because for some reason it's declared in the
90  // global scope... so just import std namespace here and use generic vsnprintf() call.
91  using namespace std;
92 
93  int size = 10;
94  char * buffer = new char[size];
95  va_list ap1;
96  va_copy(ap1, vl);
97  int nsize = vsnprintf(buffer, size, fmt, ap1);
98  if (nsize < 0) {
99  // failure: bad format probably
100  throw BadFmtsFormat("vsnprintf("+std::string(fmt)+") failure: code="+std::to_string(nsize));
101  }
102  if(size <= nsize) {
103  // buffer too small: delete buffer and try again
104  delete[] buffer;
105  size = nsize+1; // +1 for "\0"
106  buffer = new char[size];
107  nsize = vsnprintf(buffer, size, fmt, vl);
108  }
109  std::string ret(buffer);
110  delete[] buffer;
111  va_end(ap1);
112  return ret;
113 }
114 
115 
120 inline std::string fmts(const char * fmt, ...) PRINTF1_ARGS_SAFE;
121 
122 // definition. It seems definitions cannot have function attributes (here
123 // PRINTF1_ARGS_SAFE), so that's why it's separate
124 inline std::string fmts(const char * fmt, ...)
125 {
126  va_list ap;
127  va_start(ap, fmt);
128  std::string result = vfmts(fmt, ap);
129  va_end(ap);
130  return result;
131 }
132 
133 
145 #define streamstr(tokens) \
146  dynamic_cast<std::ostringstream&>( \
147  std::ostringstream().seekp(0) << tokens \
148  ).str() \
149 
150 
157 #define streamcstr(tokens) streamstr(tokens).c_str()
158 
159 
160 
161 //
162 // utility to stream an object, if possible
163 //
164 
165 namespace tomo_internal {
166 // see http://stackoverflow.com/a/9154394/1694896
167 // see sfinae_yes and sfinae_no in cxxutil.h
168 template<typename T> static auto test_has_stream_op(int)
169  -> typename sfinae_yes<decltype(*((std::ostream*)(NULL)) << *((T*)(NULL)))>::yes&;
170 template<typename T> static auto test_has_stream_op(long)
171  -> typename sfinae_no<>::no&;
172 // template<typename T, int dummy_value,
173 // typename EnabledIfType = decltype(std::declval<std::ostream&>() << std::declval<T>())>
174 // struct test_has_stream_op { static constexpr bool value = true; };
175 // template<typename T, long dummy_value>
176 // struct test_has_stream_op<T,dummy_value,void> { static constexpr bool value = false; };
177 // template<typename T>
178 // struct has_stream_op {
179 // static constexpr bool value = test_has_stream_op<T, 0>::value;
180 // };
181 } // namespace tomo_internal
182 
183 
194 template<typename T>
195 struct hasOStreamOp {
196  static constexpr bool value = (sizeof(tomo_internal::test_has_stream_op<T>(0))
197  == sizeof(typename tomo_internal::sfinae_yes<>::yes));
198 };
199 
200 
201 namespace tomo_internal {
203 template<typename T_>
204 struct StreamIfPossibleWrapper
205 {
207  typedef T_ T;
211  StreamIfPossibleWrapper(
212  const T& obj_,
213  std::string before_,
214  std::string after_,
215  std::string alternative_
216  )
217  : obj(obj_), before(before_), after(after_), alternative(alternative_)
218  {
219  }
220 
222  const T & obj;
223 
225  const std::string before;
227  const std::string after;
229  const std::string alternative;
230 
231  // internal :
232 
235  void stream_into(OStream&& stream) const
236  {
237  stream << alternative;
238  }
241  void stream_into(OStream&& stream) const
242  {
243  stream << before << obj << after;
244  }
245 };
247 template<typename T>
248 std::ostream & operator<<(std::ostream & stream, const StreamIfPossibleWrapper<T>& wobj)
249 {
250  wobj.stream_into(stream);
251  return stream;
252 }
254 template<typename T>
255 std::ostream&& operator<<(std::ostream&& stream, const StreamIfPossibleWrapper<T>& wobj)
256 {
257  wobj.stream_into(stream);
258  return std::move(stream);
259 }
260 }
261 
262 
263 
264 #ifndef TOMOGRAPHER_PARSED_BY_DOXYGEN
266 inline std::string streamIfPossible(const T& /*obj*/)
267 {
268  // obj is not streamable
269  return std::string("<")+typeid(T).name()+std::string(">");
270 }
272 inline const T& streamIfPossible(const T& obj)
273 {
274  return obj;
275 }
276 template<typename T>
277 inline tomo_internal::StreamIfPossibleWrapper<T>
278 streamIfPossible(const T& obj, std::string before,
279  std::string after = std::string(),
280  std::string alternative = "<"+std::string(typeid(T).name())+">")
281 {
282  return tomo_internal::StreamIfPossibleWrapper<T>(obj, std::move(before),
283  std::move(after), std::move(alternative));
284 }
285 #else
286 
306 template<typename T>
307 inline _Unspecified streamIfPossible(const T& obj)
308 {
309 }
341 template<typename T>
342 inline _Unspecified streamIfPossible(const T& obj,
343  std::string before,
344  std::string after = std::string(),
345  std::string alternative = "<"+std::string(typeid(T).name())+">")
346 {
347 }
348 #endif
349 
350 
351 
352 
353 
354 
355 
356 // =============================================================================
357 
358 
366 inline std::string fmtDuration(double seconds)
367 {
368  // split `seconds' into integral part and fractional part
369  double dt_i_d;
370  double dt_f = std::modf(seconds, &dt_i_d);
371  int dt_i = (int)(dt_i_d+0.5);
372 
373  return fmts("%d:%02d:%02d.%03d", dt_i/3600, (dt_i/60)%60, dt_i%60, (int)(dt_f*1000+0.5));
374 };
375 
385 template<typename Rep, typename Period>
387 {
388  typedef std::chrono::duration<Rep, Period> Duration;
389 
390  // delta-time, in seconds and fraction of seconds
391  double seconds = (double)dt.count() * Duration::period::num / Duration::period::den ;
392 
393  return fmtDuration(seconds);
394 };
395 
396 
397 
398 } // namespace Tools
399 } // namespace Tomographer
400 
401 
402 #endif
Base namespace for the Tomographer project.
Definition: densellh.h:44
std::string vfmts(const char *fmt, va_list vl)
printf- formatting to a std::string, with va_list pointer
Definition: fmt.h:83
BadFmtsFormat(const std::string &msg_)
Construct an exception for bad printf formatting. Provide an error message here.
Definition: fmt.h:69
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:366
T modf(T...args)
Exception for bad printf format.
Definition: fmt.h:64
STL class.
_Unspecified streamIfPossible(const T &obj)
Utility to stream an object, but only if "<<" overload exists.
Definition: fmt.h:307
Some C++ utilities, with a tad of C++11 tricks.
STL class.
T move(T...args)
T vsnprintf(T...args)
std::string fmts(const char *fmt,...)
printf- format to a std::string
Definition: fmt.h:124
Traits class to see whether an object exposes a "<<" operator overload for std::ostream.
Definition: fmt.h:195
VarValueDecoder< T >::RetType value(const Var &var)
Access the value of the given variable, as a C++ type.
Definition: ezmatio.h:854
T c_str(T...args)
STL class.