Simbody
3.4 (development)
|
00001 #ifndef SimTK_SimTKCOMMON_STRING_H_ 00002 #define SimTK_SimTKCOMMON_STRING_H_ 00003 00004 /* -------------------------------------------------------------------------- * 00005 * Simbody(tm): SimTKcommon * 00006 * -------------------------------------------------------------------------- * 00007 * This is part of the SimTK biosimulation toolkit originating from * 00008 * Simbios, the NIH National Center for Physics-Based Simulation of * 00009 * Biological Structures at Stanford, funded under the NIH Roadmap for * 00010 * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody. * 00011 * * 00012 * Portions copyright (c) 2005-12 Stanford University and the Authors. * 00013 * Authors: Michael Sherman * 00014 * Contributors: * 00015 * * 00016 * Licensed under the Apache License, Version 2.0 (the "License"); you may * 00017 * not use this file except in compliance with the License. You may obtain a * 00018 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. * 00019 * * 00020 * Unless required by applicable law or agreed to in writing, software * 00021 * distributed under the License is distributed on an "AS IS" BASIS, * 00022 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 00023 * See the License for the specific language governing permissions and * 00024 * limitations under the License. * 00025 * -------------------------------------------------------------------------- */ 00026 00027 // Keeps MS VC++ 8 quiet about sprintf, strcpy, etc. 00028 #ifdef _MSC_VER 00029 #pragma warning(disable:4996) 00030 #endif 00031 00032 00033 #include "SimTKcommon/internal/common.h" 00034 #include "SimTKcommon/internal/ExceptionMacros.h" 00035 00036 #include <cstdio> 00037 #include <string> 00038 #include <limits> 00039 #include <complex> 00040 #include <sstream> 00041 00042 namespace SimTK { 00043 00044 template <class N> class negator; 00045 template <class R> class conjugate; 00046 00062 class String : public std::string { 00063 public: 00064 00066 String() { } 00067 00068 // uses default copy constructor, copy assignment, and destructor 00069 00071 String(const char* s) : std::string(s) { } 00072 00074 explicit String(char c) {push_back(c);} 00075 00077 String(const std::string& s) : std::string(s) { } 00078 00081 String(const String& s, int start, int len) : std::string(s,start,len) { } 00082 00085 operator const char*() const { return c_str(); } 00086 00088 char& operator[](int i) { 00089 assert(i >= 0); 00090 return std::string::operator[]((std::string::size_type)i); 00091 } 00092 00094 char operator[](int i) const { 00095 assert(i >= 0); 00096 return std::string::operator[]((std::string::size_type)i); 00097 } 00098 00100 char& operator[](std::string::size_type i) {return std::string::operator[](i);} 00102 char operator[](std::string::size_type i) const {return std::string::operator[](i);} 00103 00106 int size() const {return (int)std::string::size();} 00107 00110 int length() const {return (int)std::string::length();} 00111 00120 explicit String(int i, const char* fmt="%d") 00121 { char buf[32]; sprintf(buf,fmt,i); (*this)=buf; } 00123 explicit String(long i, const char* fmt="%ld") 00124 { char buf[64]; sprintf(buf,fmt,i); (*this)=buf; } 00126 explicit String(long long i, const char* fmt="%lld") 00127 { char buf[64]; sprintf(buf,fmt,i); (*this)=buf; } 00129 explicit String(unsigned int s, const char* fmt="%u") 00130 { char buf[32]; sprintf(buf,fmt,s); (*this)=buf; } 00132 explicit String(unsigned long s, const char* fmt="%lu") 00133 { char buf[64]; sprintf(buf,fmt,s); (*this)=buf; } 00135 explicit String(unsigned long long s, const char* fmt="%llu") 00136 { char buf[64]; sprintf(buf,fmt,s); (*this)=buf; } 00137 00140 SimTK_SimTKCOMMON_EXPORT explicit String(float r, const char* fmt="%.7g"); 00141 00144 SimTK_SimTKCOMMON_EXPORT explicit String(double r, const char* fmt="%.15g"); 00145 00148 SimTK_SimTKCOMMON_EXPORT explicit String(long double r, 00149 const char* fmt="%.20Lg"); 00150 00154 explicit String(std::complex<float> r, const char* fmt="%.7g") 00155 { (*this)="(" + String(r.real(),fmt) + "," + String(r.imag(),fmt) + ")"; } 00159 explicit String(std::complex<double> r, const char* fmt="%.15g") 00160 { (*this)="(" + String(r.real(),fmt) + "," + String(r.imag(),fmt) + ")"; } 00165 explicit String(std::complex<long double> r, const char* fmt="%.20Lg") 00166 { (*this)="(" + String(r.real(),fmt) + "," + String(r.imag(),fmt) + ")"; } 00167 00170 explicit String(bool b) : std::string(b?"true":"false") { } 00171 00176 template <class T> inline explicit String(const T& t); // see below 00177 00180 template <class T> explicit 00181 String(const negator<T>& nt) { 00182 new (this) String(T(nt)); 00183 } 00185 template <class T> 00186 String(const negator<T>& nt, const char* fmt) { 00187 new (this) String(T(nt), fmt); 00188 } 00189 00192 template <class T> explicit 00193 String(const conjugate<T>& ct) { 00194 new (this) String(std::complex<T>(ct)); 00195 } 00197 template <class T> 00198 String(const conjugate<T>& ct, const char* fmt) { 00199 new (this) String(std::complex<T>(ct), fmt); 00200 } 00201 00202 00235 template <class T> inline bool tryConvertTo(T& out) const; // see below 00236 00243 template <class T> inline void convertTo(T& out) const; // see below 00244 00251 template <class T> T convertTo() const 00252 { T temp; convertTo<T>(temp); return temp; } 00253 00258 SimTK_SimTKCOMMON_EXPORT bool tryConvertToBool(bool& out) const; 00259 00264 SimTK_SimTKCOMMON_EXPORT bool tryConvertToFloat(float& out) const; 00265 00270 SimTK_SimTKCOMMON_EXPORT bool tryConvertToDouble(double& out) const; 00271 00276 SimTK_SimTKCOMMON_EXPORT bool tryConvertToLongDouble(long double& out) const; 00289 SimTK_SimTKCOMMON_EXPORT String& toUpper(); 00292 SimTK_SimTKCOMMON_EXPORT String& toLower(); 00296 SimTK_SimTKCOMMON_EXPORT String& trimWhiteSpace(); 00299 SimTK_SimTKCOMMON_EXPORT String& replaceAllChar(char oldChar, char newChar); 00309 static String toUpper(const std::string& in) 00310 { return String(in).toUpper(); } 00313 static String toLower(const std::string& in) 00314 { return String(in).toLower(); } 00319 static SimTK_SimTKCOMMON_EXPORT String trimWhiteSpace(const std::string& in); 00322 String& replaceAllChar(const std::string& in, char oldChar, char newChar) 00323 { return String(in).replaceAllChar(oldChar, newChar); } 00326 }; 00327 00328 // All std::stream activity should be dealt with inline so that we don't have 00329 // to worry about binary compatibility issues that can arise when passing 00330 // streams through the API. 00331 00334 template <class T> inline 00335 String::String(const T& t) { 00336 std::ostringstream stream; 00337 stream << t; 00338 *this = stream.str(); 00339 } 00340 00341 00342 // This namespace-level static method should not be necessary but gcc 4.1 00343 // still has trouble with template specialization for template member 00344 // functions. So rather than specializing the tryConvertTo() member, I'm 00345 // specializing this helper function instead. 00346 template <class T> inline static 00347 bool tryConvertStringTo(const String& value, T& out) { 00348 std::istringstream sstream(value); 00349 sstream >> out; if (sstream.fail()) return false; 00350 if (sstream.eof()) return true; 00351 // Successful conversion but didn't use all the characters. Maybe the 00352 // rest is just whitespace? 00353 std::ws(sstream); // Skip trailing whitespace if any. 00354 return sstream.eof(); // We must have used up the whole string now. 00355 } 00356 00357 // This specialization ensures that "true" and "false" are recognized as 00358 // values for bools (with any case). 00359 template <> inline 00360 bool tryConvertStringTo(const String& value, bool& out) 00361 { return value.tryConvertToBool(out); } 00362 00363 // Specialization to ensure recognition of non-finite values NaN, Inf, etc. 00364 template <> inline 00365 bool tryConvertStringTo(const String& value, float& out) 00366 { return value.tryConvertToFloat(out); } 00367 00368 // Specialization to ensure recognition of non-finite values NaN, Inf, etc. 00369 template <> inline 00370 bool tryConvertStringTo(const String& value, double& out) 00371 { return value.tryConvertToDouble(out); } 00372 00373 // Specialization to ensure recognition of non-finite values NaN, Inf, etc. 00374 template <> inline 00375 bool tryConvertStringTo(const String& value, long double& out) 00376 { return value.tryConvertToLongDouble(out); } 00377 00378 // This specialization ensures that we get the whole String including 00379 // leading and trailing white space. Of course this is not useful for 00380 // anything but may occur as a result of some higher-level templatized 00381 // method that doesn't know what type it is converting here. 00382 template<> inline 00383 bool tryConvertStringTo(const String& value, String& out) 00384 { out = value; return true; } 00385 00386 // Same as above but for std::string output rather than String. 00387 template<> inline 00388 bool tryConvertStringTo(const String& value, std::string& out) 00389 { out = value; return true; } 00390 00392 template <class T> inline 00393 bool tryConvertStringTo(const String& value, negator<T>& out) { 00394 T nonnegated; 00395 if (!tryConvertStringTo(value, nonnegated)) return false; 00396 out = nonnegated; 00397 return true; 00398 } 00399 00401 template <class T> inline 00402 bool tryConvertStringTo(const String& value, conjugate<T>& out) { 00403 std::complex<T> cmplx; 00404 if (!tryConvertStringTo(value, cmplx)) return false; 00405 out = cmplx; 00406 return true; 00407 } 00408 00409 00410 // This partial specialization ensures that you can't interpret 00411 // a String as a pointer. 00412 template<class T> inline static 00413 bool tryConvertStringTo(const String& value, T*& out) { 00414 SimTK_ERRCHK1_ALWAYS(false, "SimTK::convertStringTo(value,T*)", 00415 "Can't interpret a string as a pointer (%s*).", 00416 NiceTypeName<T>::name()); 00417 return false; 00418 } 00419 00420 template <class T> inline bool 00421 String::tryConvertTo(T& out) const 00422 { return tryConvertStringTo(*this, out); } 00423 00424 template <class T> inline void 00425 String::convertTo(T& out) const { 00426 const int MaxStr = 50; 00427 const bool convertOK = tryConvertTo<T>(out); 00428 if (convertOK) return; 00429 00430 // Make sure we don't try to output more than MaxStr characters of 00431 // the bad string in the error message. 00432 String shorter = this->substr(0, MaxStr); 00433 if (shorter.size() < this->size()) shorter += " ..."; 00434 SimTK_ERRCHK2_ALWAYS(convertOK, "String::convertTo()", 00435 "Couldn't interpret string '%s' as type T=%s.", 00436 shorter.c_str(), NiceTypeName<T>::name()); 00437 } 00438 00450 template <class T> inline static 00451 void convertStringTo(const String& in, T& out) 00452 { in.convertTo<T>(out); } 00453 00464 template <class T> inline static 00465 T convertStringTo(const String& in) 00466 { return in.convertTo<T>(); } 00467 00468 } 00469 #endif // SimTK_SimTKCOMMON_STRING_H_