mlpack
prefixedoutstream_impl.hpp
Go to the documentation of this file.
1 
13 #ifndef MLPACK_CORE_UTIL_PREFIXEDOUTSTREAM_IMPL_HPP
14 #define MLPACK_CORE_UTIL_PREFIXEDOUTSTREAM_IMPL_HPP
15 
16 // Just in case it hasn't been included.
17 #include "prefixedoutstream.hpp"
18 
19 #ifdef HAS_BFD_DL
20  #include "backtrace.hpp"
21 #endif
22 
23 #include <iostream>
24 #include <sstream>
25 
26 namespace mlpack {
27 namespace util {
28 
29 template<typename T>
31 {
32  BaseLogic<T>(s);
33  return *this;
34 }
35 
36 // For non-Armadillo types.
37 template<typename T>
38 typename std::enable_if<!arma::is_arma_type<T>::value>::type
39 PrefixedOutStream::BaseLogic(const T& val)
40 {
41  // We will use this to track whether or not we need to terminate at the end of
42  // this call (only for streams which terminate after a newline).
43  bool newlined = false;
44  std::string line;
45 
46  // If we need to, output the prefix.
47  PrefixIfNeeded();
48 
49  std::ostringstream convert;
50  // Sync flags and precision with destination stream
51  convert.setf(destination.flags());
52  convert.precision(destination.precision());
53  convert << val;
54 
55  if (convert.fail())
56  {
57  PrefixIfNeeded();
58  if (!ignoreInput)
59  {
60  destination << "Failed type conversion to string for output; output not "
61  "shown." << std::endl;
62  newlined = true;
63  }
64  }
65  else
66  {
67  line = convert.str();
68 
69  // If the length of the casted thing was 0, it may have been a stream
70  // manipulator, so send it directly to the stream and don't ask questions.
71  if (line.length() == 0)
72  {
73  // The prefix cannot be necessary at this point.
74  if (!ignoreInput) // Only if the user wants it.
75  destination << val;
76 
77  return;
78  }
79 
80  // Now, we need to check for newlines in the output and print it.
81  size_t nl;
82  size_t pos = 0;
83  while ((nl = line.find('\n', pos)) != std::string::npos)
84  {
85  PrefixIfNeeded();
86 
87  // Only output if the user wants it.
88  if (!ignoreInput)
89  {
90  destination << line.substr(pos, nl - pos);
91  destination << std::endl;
92  }
93 
94  newlined = true; // Ensure this is set for the fatal exception if needed.
95  carriageReturned = true; // Regardless of whether or not we display it.
96 
97  pos = nl + 1;
98  }
99 
100  if (pos != line.length()) // We need to display the rest.
101  {
102  PrefixIfNeeded();
103  if (!ignoreInput)
104  destination << line.substr(pos);
105  }
106  }
107 
108  // If we displayed a newline and we need to throw afterwards, do that.
109  if (fatal && newlined)
110  {
111  if (!ignoreInput)
112  destination << std::endl;
113 
114  // Print a backtrace, if we can.
115 #ifdef HAS_BFD_DL
116  if (fatal && !ignoreInput && backtrace)
117  {
118  size_t nl;
119  size_t pos = 0;
120 
121  Backtrace bt;
122  std::string btLine = bt.ToString();
123  while ((nl = btLine.find('\n', pos)) != std::string::npos)
124  {
125  PrefixIfNeeded();
126 
127  if (!ignoreInput)
128  {
129  destination << btLine.substr(pos, nl - pos);
130  destination << std::endl;
131  }
132 
133  carriageReturned = true; // Regardless of whether or not we display it.
134 
135  pos = nl + 1;
136  }
137  }
138 #endif
139 
140  throw std::runtime_error("fatal error; see Log::Fatal output");
141  }
142 }
143 
144 // For Armadillo types.
145 template<typename T>
146 typename std::enable_if<arma::is_arma_type<T>::value>::type
147 PrefixedOutStream::BaseLogic(const T& val)
148 {
149  // Extract printable object from the input.
150  const arma::Mat<typename T::elem_type>& printVal(val);
151 
152  // We will use this to track whether or not we need to terminate at the end of
153  // this call (only for streams which terminate after a newline).
154  bool newlined = false;
155  std::string line;
156 
157  // If we need to, output the prefix.
158  PrefixIfNeeded();
159 
160  std::ostringstream convert;
161 
162  // Check if the stream is in the default state.
163  if (destination.flags() == convert.flags() &&
164  destination.precision() == convert.precision())
165  {
166  printVal.print(convert);
167  }
168  else
169  {
170  // Sync flags and precision with destination stream
171  convert.setf(destination.flags());
172  convert.precision(destination.precision());
173 
174  // Set width of the convert stream.
175  const arma::Mat<typename T::elem_type>& absVal(arma::abs(printVal));
176  double maxVal = absVal.max();
177 
178  if (maxVal == 0.0)
179  maxVal = 1;
180 
181  const int maxLog = int(log10(maxVal)) + 1;
182  const int padding = 4;
183  convert.width(convert.precision() + maxLog + padding);
184  printVal.raw_print(convert);
185  }
186 
187  if (convert.fail())
188  {
189  PrefixIfNeeded();
190  if (!ignoreInput)
191  {
192  destination << "Failed type conversion to string for output; output not "
193  "shown." << std::endl;
194  newlined = true;
195  }
196  }
197  else
198  {
199  line = convert.str();
200 
201  // If the length of the casted thing was 0, it may have been a stream
202  // manipulator, so send it directly to the stream and don't ask questions.
203  if (line.length() == 0)
204  {
205  // The prefix cannot be necessary at this point.
206  if (!ignoreInput) // Only if the user wants it.
207  destination << val;
208 
209  return;
210  }
211 
212  // Now, we need to check for newlines in the output and print it.
213  size_t nl;
214  size_t pos = 0;
215  while ((nl = line.find('\n', pos)) != std::string::npos)
216  {
217  PrefixIfNeeded();
218 
219  // Only output if the user wants it.
220  if (!ignoreInput)
221  {
222  destination << line.substr(pos, nl - pos);
223  destination << std::endl;
224  }
225 
226  newlined = true; // Ensure this is set for the fatal exception if needed.
227  carriageReturned = true; // Regardless of whether or not we display it.
228 
229  pos = nl + 1;
230  }
231 
232  if (pos != line.length()) // We need to display the rest.
233  {
234  PrefixIfNeeded();
235  if (!ignoreInput)
236  destination << line.substr(pos);
237  }
238  }
239 
240  // If we displayed a newline and we need to throw afterwards, do that.
241  if (fatal && newlined)
242  {
243  if (!ignoreInput)
244  destination << std::endl;
245 
246  // Print a backtrace, if we can.
247 #ifdef HAS_BFD_DL
248  if (fatal && !ignoreInput)
249  {
250  size_t nl;
251  size_t pos = 0;
252 
253  Backtrace bt;
254  std::string btLine = bt.ToString();
255  while ((nl = btLine.find('\n', pos)) != std::string::npos)
256  {
257  PrefixIfNeeded();
258 
259  if (!ignoreInput)
260  {
261  destination << btLine.substr(pos, nl - pos);
262  destination << std::endl;
263  }
264 
265  carriageReturned = true; // Regardless of whether or not we display it.
266 
267  pos = nl + 1;
268  }
269  }
270 #endif
271 
272  throw std::runtime_error("fatal error; see Log::Fatal output");
273  }
274 }
275 
276 // This is an inline function (that is why it is here and not in .cc).
277 void PrefixedOutStream::PrefixIfNeeded()
278 {
279  // If we need to, output a prefix.
280  if (carriageReturned)
281  {
282  if (!ignoreInput) // But only if we are allowed to.
283  destination << prefix;
284 
285  carriageReturned = false; // Denote that the prefix has been displayed.
286  }
287 }
288 
289 } // namespace util
290 } // namespace mlpack
291 
292 #endif // MLPACK_CORE_UTIL_PREFIXEDOUTSTREAM_IMPL_HPP
std::ostream & destination
The output stream that all data is to be sent to; example: MLPACK_COUT_STREAM.
Definition: prefixedoutstream.hpp:116
Linear algebra utility functions, generally performed on matrices or vectors.
Definition: cv.hpp:1
PrefixedOutStream & operator<<(bool val)
Write a bool to the stream.
Definition: prefixedoutstream.cpp:25
bool ignoreInput
Discards input, prints nothing if true.
Definition: prefixedoutstream.hpp:119
std::string ToString()
Returns string of backtrace.
Definition: backtrace.cpp:168
Allows us to output to an ostream with a prefix at the beginning of each line, in the same way we wou...
Definition: prefixedoutstream.hpp:46
bool backtrace
If true, on a fatal error, a backtrace will be printed if HAS_BFD_DL is defined.
Definition: prefixedoutstream.hpp:123
Provides a backtrace.
Definition: backtrace.hpp:46