source: trunk/FACT++/src/tools.cc@ 19127

Last change on this file since 19127 was 19119, checked in by tbretz, 6 years ago
Added Fractional as a complement to scientific.
File size: 8.6 KB
Line 
1// **************************************************************************
2/** @file tools.cc
3
4@todo
5 - Resolve the dependancies with dim
6 - Move code to a more appropriate place
7 - put stuff in namespaces
8*/
9// **************************************************************************
10#include "tools.h"
11
12#include <stdarg.h>
13#include <iomanip>
14#include <sstream>
15
16#include <boost/tokenizer.hpp>
17#include <boost/algorithm/string.hpp>
18
19using namespace std;
20
21string Tools::Format(const char *fmt, va_list &ap)
22{
23 int n=256;
24
25 char *ret=0;
26 while (1)
27 {
28 ret = new char[n+1];
29
30 const int sz = vsnprintf(ret, n, fmt, ap);
31 if (sz<=n)
32 break;
33
34 n *= 2;
35 delete [] ret;
36 };
37
38 string str(ret);
39
40 delete [] ret;
41
42 return str;
43}
44
45string Tools::Form(const char *fmt, ...)
46{
47 va_list ap;
48 va_start(ap, fmt);
49
50 string str = Format(fmt, ap);
51
52 va_end(ap);
53
54 return str;
55}
56
57// --------------------------------------------------------------------------
58//
59//! This is a static helper to remove leading and trailing whitespaces.
60//!
61//! @param buf
62//! a pointer to the char array from which the whitespaces should be
63//! removed
64//!
65//! @returns
66//! a std::string with the whitespaces removed from buf
67//
68string Tools::Trim(const string &str)
69{
70 // Trim Both leading and trailing spaces
71 const size_t start = str.find_first_not_of(' '); // Find the first character position after excluding leading blank spaces
72 const size_t end = str.find_last_not_of(' '); // Find the first character position from reverse af
73
74 // if all spaces or empty return an empty string
75 if (string::npos==start || string::npos==end)
76 return string();
77
78 return str.substr(start, end-start+1);
79}
80
81// --------------------------------------------------------------------------
82//
83//! This is a static helper to remove leading and trailing whitespaces and
84//! if available leading and trailing quotes, can be either ' or "
85//!
86//! @param buf
87//! a pointer to the char array to be trimmed
88//!
89//! @returns
90//! a std::string with the content trimmed
91//
92string Tools::TrimQuotes(const string &str)
93{
94 string rc = Trim(str);
95 if (rc.length()<2)
96 return rc;
97
98 const char b = rc[0];
99 const char e = rc[rc.length()-1];
100
101 if ((b=='\"' && e=='\"') || (b=='\'' && e=='\''))
102 return rc.substr(1, rc.length()-2);
103
104 return rc;
105}
106
107// --------------------------------------------------------------------------
108//
109//! This is a static helper to remove leading and trailing whitespaces.
110//!
111//! Usage example:
112//!
113//! \code
114//! string str = " Dies ist ein test fuer einen ganz langen Satz "
115//! "und ob er korrekt umgebrochen und formatiert wird. Alles "
116//! "nur ein simpler test aber trotzdem ganz wichtig.";
117//!
118//! cout << setfill('-') << setw(40) << "+" << endl;
119//! while (1)
120//! {
121//! const string rc = Tools::Wrap(str, 40);
122//! if (rc.empty())
123//! break;
124//! cout << rc << endl;
125//! }
126//! \endcode
127//!
128string Tools::Wrap(string &str, size_t width)
129{
130 const size_t pos = str.length()<width ? string::npos : str.find_last_of(' ', width);
131 if (pos==string::npos)
132 {
133 const string rc = str;
134 str = "";
135 return rc;
136 }
137
138 const size_t indent = str.find_first_not_of(' ');
139
140 const string rc = str.substr(0, pos);
141 const size_t p2 = str.find_first_not_of(' ', pos+1);
142
143 str = str.substr(0, indent) + str.substr(p2==string::npos ? pos+1 : p2);
144
145 return rc;
146}
147
148string Tools::Scientific(uint64_t val)
149{
150 ostringstream rc;
151 rc << setprecision(1) << fixed;
152
153 if (val<1000)
154 {
155 rc << val << " ";
156 return rc.str();
157 }
158
159 if (val<3000)
160 {
161 rc << val/1000. << " k";
162 return rc.str();
163 }
164
165 if (val<1000000)
166 {
167 rc << val/1000 << " k";
168 return rc.str();
169 }
170
171 if (val<3000000)
172 {
173 rc << val/1000000. << " M";
174 return rc.str();
175 }
176
177 if (val<1000000000)
178 {
179 rc << val/1000000 << " M";
180 return rc.str();
181 }
182
183 if (val<3000000000)
184 {
185 rc << val/1000000000. << " G";
186 return rc.str();
187 }
188
189 if (val<1000000000000)
190 {
191 rc << val/1000000000 << " G";
192 return rc.str();
193 }
194
195 if (val<3000000000000)
196 {
197 rc << val/1000000000000. << " T";
198 return rc.str();
199 }
200
201 if (val<1000000000000000)
202 {
203 rc << val/1000000000000 << " T";
204 return rc.str();
205 }
206
207 if (val<3000000000000000)
208 {
209 rc << val/1000000000000000. << " P";
210 return rc.str();
211 }
212
213 rc << val/1000000000000000. << " P";
214 return rc.str();
215}
216
217string Tools::Fractional(const double &val)
218{
219 ostringstream rc;
220 rc << setprecision(1) << fixed;
221
222 const auto abs = fabs(val);
223
224 if (abs>1)
225 {
226 rc << val << " ";
227 return rc.str();
228 }
229
230 if (abs>1e-3)
231 {
232 rc << val*1000 << " m";
233 return rc.str();
234 }
235
236 if (abs>1e-6)
237 {
238 rc << val*1000000 << " u";
239 return rc.str();
240 }
241
242 if (abs>1e-9)
243 {
244 rc << val*1000000000 << " n";
245 return rc.str();
246 }
247
248 if (abs>1e-12)
249 {
250 rc << val*1000000000000. << " p";
251 return rc.str();
252 }
253
254 rc << abs*1000000000000000. << " f";
255 return rc.str();
256}
257
258// --------------------------------------------------------------------------
259//
260//! Splits a string into a filename and command line arguments, like:
261//!
262//! file.txt arg1=argument1 arg2="argument 2" arg3="argument \"3\""
263//!
264//! 'file.txt' will be returned on opt, the arguments will be returned in
265//! the returned map.
266//!
267//! If the returned file name is empty, an error has occured:
268//! If the map is also empty the file name was empty, if the map has
269//! one entry then for this entry the equal sign was missing.
270//
271//! allow==true allows for positional (empty) arguments, like in
272//! file.txt arg1 arg2="argument 2" arg3
273//!
274map<string,string> Tools::Split(string &opt, bool allow)
275{
276 using namespace boost;
277 typedef escaped_list_separator<char> separator;
278
279 const string data(opt);
280
281 const tokenizer<separator> tok(data, separator("\\", " ", "\"'"));
282
283 auto it=tok.begin();
284 if (it==tok.end())
285 {
286 opt = "";
287 return map<string,string>();
288 }
289
290 opt = string(*it).find_first_of('=')==string::npos ? *it++ : "";
291
292 map<string,string> rc;
293
294 int cnt=0;
295
296 for (; it!=tok.end(); it++)
297 {
298 if (it->empty())
299 continue;
300
301 const size_t pos = it->find_first_of('=');
302 if (pos==string::npos)
303 {
304 if (allow)
305 {
306 rc[to_string(cnt++)] = *it;
307 continue;
308 }
309
310 opt = "";
311 rc.clear();
312 rc[*it] = "";
313 return rc;
314 }
315
316 rc[it->substr(0, pos)] = it->substr(pos+1);
317 }
318
319 return rc;
320}
321
322vector<string> Tools::Split(const string &str, const string &delim)
323{
324 vector<string> rc;
325 boost::split(rc, str, boost::is_any_of(delim));
326 return rc;
327}
328
329// --------------------------------------------------------------------------
330//
331//! Returns the string with a comment (introduced by a #) stripped. The
332//! comment mark can be escaped by either \# or "#"
333//!
334string Tools::Uncomment(const string &opt)
335{
336 using namespace boost;
337 typedef escaped_list_separator<char> separator;
338
339 const auto it = tokenizer<separator>(opt, separator("\\", "#", "\"'")).begin();
340
341 const int charPos = it.base() - opt.begin();
342
343 return charPos<1 ? "" : opt.substr(0, opt[charPos-1]=='#' ? charPos-1 : charPos);
344}
345
346// --------------------------------------------------------------------------
347//
348//! Wraps a given text into a vector of strings with not more than
349//! max size lines
350//!
351vector<string> Tools::WordWrap(string text, const uint16_t &max)
352{
353 if (text.size()<max)
354 return { text };
355
356 vector<string> rc;
357 while (1)
358 {
359 // Remove trailing white spaces
360 const size_t st = text.find_first_not_of(' ');
361 if (st==string::npos)
362 break;
363
364 text.erase(0, st);
365 if (text.size()<max)
366 {
367 rc.push_back(text);
368 break;
369 }
370
371 // Last white space - position to break
372 const size_t ws = text.find_last_of(' ', max);
373 if (ws==string::npos)
374 {
375 rc.push_back(text.substr(0, max));
376 text.erase(0, max);
377 continue;
378 }
379
380 // Previous non-whitespace, last position to keep
381 const size_t ch = text.find_last_not_of(' ', ws);
382 if (ch==string::npos) // found only white spaces
383 continue;
384
385 rc.push_back(text.substr(0, ch+1));
386 text.erase(0, ws);
387 }
388
389 return rc;
390}
Note: See TracBrowser for help on using the repository browser.