Simbody  3.8
String.h
Go to the documentation of this file.
1 #ifndef SimTK_SimTKCOMMON_STRING_H_
2 #define SimTK_SimTKCOMMON_STRING_H_
3 
4 /* -------------------------------------------------------------------------- *
5  * Simbody(tm): SimTKcommon *
6  * -------------------------------------------------------------------------- *
7  * This is part of the SimTK biosimulation toolkit originating from *
8  * Simbios, the NIH National Center for Physics-Based Simulation of *
9  * Biological Structures at Stanford, funded under the NIH Roadmap for *
10  * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody. *
11  * *
12  * Portions copyright (c) 2005-15 Stanford University and the Authors. *
13  * Authors: Michael Sherman *
14  * Contributors: *
15  * *
16  * Licensed under the Apache License, Version 2.0 (the "License"); you may *
17  * not use this file except in compliance with the License. You may obtain a *
18  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. *
19  * *
20  * Unless required by applicable law or agreed to in writing, software *
21  * distributed under the License is distributed on an "AS IS" BASIS, *
22  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
23  * See the License for the specific language governing permissions and *
24  * limitations under the License. *
25  * -------------------------------------------------------------------------- */
26 
29 
30 #include <iomanip>
31 #include <cstdio>
32 #include <string>
33 #include <limits>
34 #include <complex>
35 #include <sstream>
36 
37 // Keeps MS VC++ quiet about sprintf, strcpy, etc.
38 #ifdef _MSC_VER
39 #pragma warning(push)
40 #pragma warning(disable:4996)
41 #endif
42 
43 namespace SimTK {
44 
46 
47 template <class N> class negator;
48 template <class R> class conjugate;
49 
65 class String : public std::string {
66 public:
67 
69 String() { }
70 
71 // uses default copy constructor, copy assignment, and destructor
72 
74 String(const char* s) : std::string(s) { }
75 
77 explicit String(char c) {push_back(c);}
78 
80 String(const std::string& s) : std::string(s) { }
81 
84 String(const String& s, int start, int len) : std::string(s,start,len) { }
85 
88 operator const char*() const { return c_str(); }
89 
91 char& operator[](int i) {
92  assert(i >= 0);
93  return std::string::operator[]((std::string::size_type)i);
94 }
95 
97 char operator[](int i) const {
98  assert(i >= 0);
99  return std::string::operator[]((std::string::size_type)i);
100 }
101 
103 char& operator[](std::string::size_type i) {return std::string::operator[](i);}
105 char operator[](std::string::size_type i) const {return std::string::operator[](i);}
106 
109 int size() const {return (int)std::string::size();}
110 
113 int length() const {return (int)std::string::length();}
114 
123 explicit String(int i, const char* fmt="%d")
124 { const int n=32; char buf[n]; snprintf(buf,n,fmt,i); (*this)=buf; }
126 explicit String(long i, const char* fmt="%ld")
127 { const int n=64; char buf[n]; snprintf(buf,n,fmt,i); (*this)=buf; }
129 explicit String(long long i, const char* fmt="%lld")
130 { const int n=64; char buf[n]; snprintf(buf,n,fmt,i); (*this)=buf; }
132 explicit String(unsigned int s, const char* fmt="%u")
133 { const int n=32; char buf[n]; snprintf(buf,n,fmt,s); (*this)=buf; }
135 explicit String(unsigned long s, const char* fmt="%lu")
136 { const int n=64; char buf[n]; snprintf(buf,n,fmt,s); (*this)=buf; }
138 explicit String(unsigned long long s, const char* fmt="%llu")
139 { const int n=64; char buf[n]; snprintf(buf,n,fmt,s); (*this)=buf; }
140 
145 SimTK_SimTKCOMMON_EXPORT explicit String(float r, const char* fmt="%.9g");
146 
151 SimTK_SimTKCOMMON_EXPORT explicit String(double r, const char* fmt="%.17g");
152 
156 explicit String(std::complex<float> r, const char* fmt="%.9g")
157 { (*this)="(" + String(r.real(),fmt) + "," + String(r.imag(),fmt) + ")"; }
161 explicit String(std::complex<double> r, const char* fmt="%.17g")
162 { (*this)="(" + String(r.real(),fmt) + "," + String(r.imag(),fmt) + ")"; }
163 
166 explicit String(bool b) : std::string(b?"true":"false") { }
167 
174 template <class T> inline explicit
175 String(const T& t);
176 
186 template <class T> inline explicit
187 String(const T& t, int precision);
188 
191 template <class T> explicit
192 String(const negator<T>& nt) {
193  new (this) String(T(nt));
194 }
196 template <class T>
197 String(const negator<T>& nt, const char* fmt) {
198  new (this) String(T(nt), fmt);
199 }
200 
203 template <class T> explicit
204 String(const conjugate<T>& ct) {
205  new (this) String(std::complex<T>(ct));
206 }
208 template <class T>
209 String(const conjugate<T>& ct, const char* fmt) {
210  new (this) String(std::complex<T>(ct), fmt);
211 }
212 
213 
246 template <class T> inline bool tryConvertTo(T& out) const; // see below
247 
254 template <class T> inline void convertTo(T& out) const; // see below
255 
262 template <class T> T convertTo() const
263 { T temp; convertTo<T>(temp); return temp; }
264 
270 
276 
304 SimTK_SimTKCOMMON_EXPORT String& replaceAllChar(char oldChar, char newChar);
314 static String toUpper(const std::string& in)
315 { return String(in).toUpper(); }
318 static String toLower(const std::string& in)
319 { return String(in).toLower(); }
324 static SimTK_SimTKCOMMON_EXPORT String trimWhiteSpace(const std::string& in);
327 String& replaceAllChar(const std::string& in, char oldChar, char newChar)
328 { return String(in).replaceAllChar(oldChar, newChar); }
331 };
332 
333 // All std::stream activity should be dealt with inline so that we don't have
334 // to worry about binary compatibility issues that can arise when passing
335 // streams through the API.
336  // Hide from Doxygen
338 template <class T> inline
339 auto stringStreamInsertHelper(std::ostringstream& os, const T& t, bool)
340  -> decltype(static_cast<std::ostringstream&>(os << t)) {
341  os << t;
342  return os;
343 }
344 
345 
346 template <class T> inline
347 auto stringStreamInsertHelper(std::ostringstream& os, const T& t, int)
348  -> std::ostringstream& {
349  SimTK_ERRCHK1_ALWAYS(!"no stream insertion operator", "String::String(T)",
350  "Type T=%s has no stream insertion operator<<(T) and there "
351  "is no specialized String(T) constructor.",
352  NiceTypeName<T>::namestr().c_str());
353  return os;
354 }
355 
356 template <class T> inline
357 auto stringStreamExtractHelper(std::istringstream& is, T& t, bool)
358  -> decltype(static_cast<std::istringstream&>(is >> t)) {
359  is >> t;
360  return is;
361 }
362 
363 template <class T> inline
364 auto stringStreamExtractHelper(std::istringstream& is, T& t, int)
365  -> std::istringstream& {
366  SimTK_ERRCHK1_ALWAYS(!"no stream extraction operator",
367  "String::tryConvertTo<T>()",
368  "Type T=%s has no stream extraction operator>>(T) and there "
369  "is no specialized tryConvertTo<T>() constructor.",
370  NiceTypeName<T>::namestr().c_str());
371  return is;
372 }
373 
376 // Implementation of the generic templatized String constructor.
377 template <class T> inline
378 String::String(const T& t) {
379  std::ostringstream os;
380  *this = stringStreamInsertHelper(os, t, true).str();
381 }
382 
383 // Implementation of the generic templatized String constructor
384 // with precision.
385 // To ensure consistent behavior of ostream::setprecision() across operating
386 // systems and whether a build is debug or release, precision is bounded:
387 // 1 <= precision <= SimTK::LosslessNumDigitsReal
388 template <class T> inline
389 String::String(const T& t, int precision) {
390  std::ostringstream os;
391  if(precision < 1)
392  precision = 1;
393  else if(precision > SimTK::LosslessNumDigitsReal)
394  precision = SimTK::LosslessNumDigitsReal;
395  os << std::setprecision(precision);
396  *this = stringStreamInsertHelper(os, t, true).str();
397 }
398 
399 
400 // This namespace-level static method should not be necessary but gcc 4.1
401 // still has trouble with template specialization for template member
402 // functions. So rather than specializing the tryConvertTo() member, I'm
403 // specializing this helper function instead.
404 template <class T> inline static
405 bool tryConvertStringTo(const String& value, T& out) {
406  std::istringstream sstream(value);
407  stringStreamExtractHelper(sstream, out, true);
408  if (sstream.fail()) return false;
409  if (sstream.eof()) return true;
410  // Successful conversion but didn't use all the characters. Maybe the
411  // rest is just whitespace?
412  std::ws(sstream); // Skip trailing whitespace if any.
413  return sstream.eof(); // We must have used up the whole string now.
414 }
415 
416 // This specialization ensures that "true" and "false" are recognized as
417 // values for bools (with any case).
418 template <> inline
419 bool tryConvertStringTo(const String& value, bool& out)
420 { return value.tryConvertToBool(out); }
421 
422 // Specialization to ensure recognition of non-finite values NaN, Inf, etc.
423 template <> inline
424 bool tryConvertStringTo(const String& value, float& out)
425 { return value.tryConvertToFloat(out); }
426 
427 // Specialization to ensure recognition of non-finite values NaN, Inf, etc.
428 template <> inline
429 bool tryConvertStringTo(const String& value, double& out)
430 { return value.tryConvertToDouble(out); }
431 
432 // This specialization ensures that we get the whole String including
433 // leading and trailing white space. Of course this is not useful for
434 // anything but may occur as a result of some higher-level templatized
435 // method that doesn't know what type it is converting here.
436 template<> inline
437 bool tryConvertStringTo(const String& value, String& out)
438 { out = value; return true; }
439 
440 // Same as above but for std::string output rather than String.
441 template<> inline
442 bool tryConvertStringTo(const String& value, std::string& out)
443 { out = value; return true; }
444 
446 template <class T> inline
447 bool tryConvertStringTo(const String& value, negator<T>& out) {
448  T nonnegated;
449  if (!tryConvertStringTo(value, nonnegated)) return false;
450  out = nonnegated;
451  return true;
452 }
453 
455 template <class T> inline
456 bool tryConvertStringTo(const String& value, conjugate<T>& out) {
457  std::complex<T> cmplx;
458  if (!tryConvertStringTo(value, cmplx)) return false;
459  out = cmplx;
460  return true;
461 }
462 
463 
464 // This partial specialization ensures that you can't interpret
465 // a String as a pointer.
466 template<class T> inline static
467 bool tryConvertStringTo(const String& value, T*& out) {
468  SimTK_ERRCHK1_ALWAYS(false, "SimTK::convertStringTo(value,T*)",
469  "Can't interpret a string as a pointer (%s*).",
470  NiceTypeName<T>::namestr().c_str());
471  return false;
472 }
473 
474 template <class T> inline bool
475 String::tryConvertTo(T& out) const
476 { return tryConvertStringTo(*this, out); }
477 
478 template <class T> inline void
479 String::convertTo(T& out) const {
480  const int MaxStr = 50;
481  const bool convertOK = tryConvertTo<T>(out);
482  if (convertOK) return;
483 
484  // Make sure we don't try to output more than MaxStr characters of
485  // the bad string in the error message.
486  String shorter = this->substr(0, MaxStr);
487  if (shorter.size() < this->size()) shorter += " ...";
488  SimTK_ERRCHK2_ALWAYS(convertOK, "String::convertTo()",
489  "Couldn't interpret string '%s' as type T=%s.",
490  shorter.c_str(), NiceTypeName<T>::namestr().c_str());
491 }
492 
504 template <class T> inline static
505 void convertStringTo(const String& in, T& out)
506 { in.convertTo<T>(out); }
507 
518 template <class T> inline static
520 { return in.convertTo<T>(); }
521 
522 } // namespace SimTK
523 
524 #ifdef _MSC_VER
525 #pragma warning(pop)
526 #endif
527 
528 #endif // SimTK_SimTKCOMMON_STRING_H_
This file contains macros which are convenient to use for sprinkling error checking around liberally ...
#define SimTK_ERRCHK2_ALWAYS(cond, whereChecked, fmt, a1, a2)
Definition: ExceptionMacros.h:289
#define SimTK_ERRCHK1_ALWAYS(cond, whereChecked, fmt, a1)
Definition: ExceptionMacros.h:285
Mandatory first inclusion for any Simbody source or header file.
#define SimTK_SimTKCOMMON_EXPORT
Definition: SimTKcommon/include/SimTKcommon/internal/common.h:224
SimTK::String is a plug-compatible std::string replacement (plus some additional functionality) inten...
Definition: String.h:65
char & operator[](int i)
Add operator[] that takes int index instead of size_type.
Definition: String.h:91
char operator[](std::string::size_type i) const
Pass through to string::operator[].
Definition: String.h:105
int size() const
Override std::string size() method to return an int instead of the inconvenient unsigned type size_ty...
Definition: String.h:109
static String toLower(const std::string &in)
Downshift the given std::string returning a new SimTK::String in which all the letters have be made l...
Definition: String.h:318
String(const char *s)
This is an implicit conversion from const char* to String.
Definition: String.h:74
String(const conjugate< T > &ct)
Constructing a String from a conjugate value converts to the underlying complex type and then uses on...
Definition: String.h:204
String & replaceAllChar(char oldChar, char newChar)
Substitute in place newChar for oldChar wherever oldChar appears in this String.
static void convertStringTo(const String &in, T &out)
This method converts its String argument to type T and returns it into the variable supplied as its s...
Definition: String.h:505
String(const negator< T > &nt, const char *fmt)
Same, but allows for format specification.
Definition: String.h:197
String(const negator< T > &nt)
Constructing a String from a negated value converts to the underlying native type and then uses one o...
Definition: String.h:192
String(unsigned long s, const char *fmt="%lu")
Format an unsigned long as a printable String.
Definition: String.h:135
String(char c)
We allow creating a String from a char but you have to do it explicitly.
Definition: String.h:77
char & operator[](std::string::size_type i)
Pass through to string::operator[].
Definition: String.h:103
String(const conjugate< T > &ct, const char *fmt)
Same, but allows for format specification.
Definition: String.h:209
String(long long i, const char *fmt="%lld")
Format a long long as a printable String.
Definition: String.h:129
String(std::complex< float > r, const char *fmt="%.9g")
Format a complex<float> as a printable String (real,imag) with parentheses and a comma as shown.
Definition: String.h:156
String()
Default constructor produces an empty string.
Definition: String.h:69
String & toLower()
Downshift the given String in place, so that uppercase letters are replaced with their lowercase equi...
bool tryConvertToDouble(double &out) const
Special-purpose method for interpreting this String as a double.
String(unsigned int s, const char *fmt="%u")
Format an unsigned int as a printable String.
Definition: String.h:132
static T convertStringTo(const String &in)
This method converts its String argument to type T and returns it as its function value; this is part...
Definition: String.h:519
int length() const
Override std::string length() method to return an int instead of the inconvenient unsigned type size_...
Definition: String.h:113
String(float r, const char *fmt="%.9g")
Format a float as a printable String.
String & toUpper()
Upshift the given String in place, so that lowercase letters are replaced with their uppercase equiva...
String(const String &s, int start, int len)
Construct a String as a copy of a substring beginning at position start with length len.
Definition: String.h:84
String(double r, const char *fmt="%.17g")
Format a double as a printable String.
String(std::complex< double > r, const char *fmt="%.17g")
Format a complex<double> as a printable String (real,imag) with parentheses and a comma as shown.
Definition: String.h:161
String(const std::string &s)
This is an implicit conversion from std::string to String.
Definition: String.h:80
bool tryConvertToBool(bool &out) const
Special-purpose method for interpreting this String as a bool.
String & trimWhiteSpace()
Trim this String in place, removing all the initial leading and trailing white space,...
bool tryConvertTo(T &out) const
Attempt to convert this String to an object of type T, returning a status value to indicate success o...
Definition: String.h:475
static String trimWhiteSpace(const std::string &in)
Copy the input std::string to a new SimTK::String leaving off all the initial leading and trailing wh...
String(int i, const char *fmt="%d")
Format an int as a printable String.
Definition: String.h:123
String & replaceAllChar(const std::string &in, char oldChar, char newChar)
Copy the input std::string to a new SimTK::String while substituting newChar for oldChar wherever old...
Definition: String.h:327
String(long i, const char *fmt="%ld")
Format a long as a printable String.
Definition: String.h:126
static String toUpper(const std::string &in)
Upshift the given std::string returning a new SimTK::String in which all the letters have been made u...
Definition: String.h:314
T convertTo() const
A more convenient form of convertTo<T>() that returns the result as its function argument,...
Definition: String.h:262
void convertTo(T &out) const
Convert this String to an object of type T using the tryConvertTo<T>() method but throwing an error o...
Definition: String.h:479
String(unsigned long long s, const char *fmt="%llu")
Format an unsigned long long as a printable String.
Definition: String.h:138
bool tryConvertToFloat(float &out) const
Special-purpose method for interpreting this String as a float.
String(bool b)
Format a bool as a printable String "true" or "false"; if you want "1" or "0" cast the bool to an int...
Definition: String.h:166
char operator[](int i) const
Add operator[] that takes int index instead of size_type.
Definition: String.h:97
SimTK::conjugate<R> should be instantiated only for float, double.
Definition: conjugate.h:178
negator<N>, where N is a number type (real, complex, conjugate), is represented in memory identically...
Definition: negator.h:75
const int LosslessNumDigitsReal
This is the smallest number of decimal digits you should store in a text file if you want to be able ...
Definition: Scalar.h:142
This is the top-level SimTK namespace into which all SimTK names are placed to avoid collision with o...
Definition: Assembler.h:37
static bool tryConvertStringTo(const String &value, T &out)
Definition: String.h:405
Obtain human-readable and XML-usable names for arbitrarily-complicated C++ types.
Definition: SimTKcommon/include/SimTKcommon/internal/common.h:862
static const std::string & namestr()
The default implementation of namestr() attempts to return a nicely demangled and canonicalized type ...
Definition: SimTKcommon/include/SimTKcommon/internal/common.h:871