string_convert.h
Go to the documentation of this file.
00001 //
00002 //  Copyright (c) Benjamin Kaufmann
00003 //
00004 //  This is free software; you can redistribute it and/or modify
00005 //  it under the terms of the GNU General Public License as published by
00006 //  the Free Software Foundation; either version 2 of the License, or
00007 //  (at your option) any later version. 
00008 // 
00009 //  This file is distributed in the hope that it will be useful,
00010 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 //  GNU General Public License for more details.
00013 //
00014 //  You should have received a copy of the GNU General Public License
00015 //  along with this file; if not, write to the Free Software
00016 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 //
00018 #ifndef BK_LIB_STRING_CONVERT_H_INCLUDED
00019 #define BK_LIB_STRING_CONVERT_H_INCLUDED
00020 #include <cstring>
00021 #include <string>
00022 #include <vector>
00023 #include <utility>
00024 #include <stdexcept>
00025 #include <typeinfo>
00026 #include <istream>
00027 #if !defined(_MSC_VER)
00028 #include <strings.h>
00029 #else
00030 inline int strcasecmp(const char* lhs, const char* rhs)            { return _stricmp(lhs, rhs); }
00031 inline int strncasecmp(const char* lhs, const char* rhs, size_t n) { return _strnicmp(lhs, rhs, n); }
00032 #endif
00033 namespace bk_lib { namespace detail {
00034 // A primitive input stream buffer for fast extraction from a given string
00035 // NOTE: The input string is NOT COPIED, hence it 
00036 //       MUST NOT CHANGE during extraction
00037 template<class T, class Traits = std::char_traits<T> >
00038 class input_from_string : public std::basic_streambuf<T, Traits> {
00039         typedef std::basic_streambuf<T, Traits>   base_type;
00040         typedef typename Traits::char_type*       pointer_type;
00041         typedef const typename Traits::char_type* const_pointer_type;
00042         typedef typename base_type::pos_type      pos_type;
00043         typedef typename base_type::off_type      off_type;
00044 public:
00045         explicit input_from_string(const_pointer_type p, size_t size)
00046                 : buffer_(const_cast<pointer_type>(p))
00047                 , size_(size) {
00048                 base_type::setp(0, 0); // no write buffer
00049                 base_type::setg(buffer_, buffer_, buffer_+size_); // read buffer
00050         }
00051         pos_type seekoff(off_type offset, std::ios_base::seekdir dir, std::ios_base::openmode which) {
00052                 if(which & std::ios_base::out) {
00053                         // not supported!
00054                         return base_type::seekoff(offset, dir, which);
00055                 }
00056                 if(dir == std::ios_base::cur) {
00057                         offset += static_cast<off_type>(base_type::gptr() - base_type::eback());
00058                 }
00059                 else if(dir == std::ios_base::end) {
00060                         offset = static_cast<off_type>(size_) - offset;
00061                 }
00062                 return seekpos(offset, which);
00063         }
00064         pos_type seekpos(pos_type offset, std::ios_base::openmode which) {
00065                 if((which & std::ios_base::out) == 0 && offset >= pos_type(0) && ((size_t)offset) <= size_) {
00066                         base_type::setg(buffer_, buffer_+(size_t)offset, buffer_+size_);
00067                         return offset;
00068                 }
00069                 return base_type::seekpos(offset, which);
00070         }
00071 private:
00072         input_from_string(const input_from_string&);
00073         input_from_string& operator=(const input_from_string&);
00074 protected:
00075         pointer_type buffer_;
00076         size_t       size_;
00077 };
00078 
00079 template<class T, class Traits = std::char_traits<T> >
00080 class input_stream : public std::basic_istream<T, Traits> {
00081 public:
00082         input_stream(const std::string& str)
00083                 : std::basic_istream<T, Traits>(0)
00084                 , buffer_(str.data(), str.size()) {
00085                 std::basic_istream<T, Traits>::rdbuf(&buffer_);
00086         }
00087         input_stream(const char* x, size_t size)
00088                 : std::basic_istream<T, Traits>(0)
00089                 , buffer_(x, size) {
00090                 std::basic_istream<T, Traits>::rdbuf(&buffer_);
00091         }
00092 private:
00093         input_from_string<T, Traits> buffer_;
00094 };
00095 struct no_stream_support { template <class T> no_stream_support(const T&) {} };
00096 no_stream_support& operator >> (std::istream&, const no_stream_support&);
00097 } 
00099 // primitive parser
00101 template <class T>
00102 int xconvert(const char* x, T& out, const char** errPos = 0, double = 0);
00103 int xconvert(const char* x, bool& out, const char** errPos = 0, int = 0);
00104 int xconvert(const char* x, char& out, const char** errPos = 0, int = 0);
00105 int xconvert(const char* x, unsigned& out, const char** errPos = 0, int = 0);
00106 int xconvert(const char* x, int& out, const char** errPos = 0, int = 0);
00107 int xconvert(const char* x, long& out, const char** errPos = 0, int = 0);
00108 int xconvert(const char* x, unsigned long& out, const char** errPos = 0, int = 0);
00109 int xconvert(const char* x, double& out, const char** errPos = 0, int = 0);
00110 int xconvert(const char* x, const char*& out, const char** errPos = 0, int = 0);
00111 int xconvert(const char* x, std::string& out, const char** errPos = 0, int sep = 0);
00113 // composite parser
00115 const int def_sep = int(',');
00116 // parses T[,U] optionally enclosed in parentheses
00117 template <class T, class U>
00118 int xconvert(const char* x, std::pair<T, U>& out, const char** errPos = 0, int sep = def_sep) {
00119         if (!x) { return 0; }
00120         if (sep == 0) { sep = def_sep; }
00121         std::pair<T, U> temp(out);
00122         const char* n = x;
00123         int ps = 0;
00124         if (*n == '(') { ++ps; ++n; }
00125         int tokT = xconvert(n, temp.first, &n, sep);
00126         int tokU = tokT && *n == (char)sep ? xconvert(n+1, temp.second, &n, sep) : 0;
00127         int sum  = 0;
00128         if (!ps || *n == ')') {
00129                 n += ps;
00130                 if (tokU)        { out.second= temp.second; ++sum; }
00131                 if (tokU || !*n) { out.first = temp.first; ++sum; }
00132         }
00133         if (!sum) { n = x; }
00134         if (errPos) *errPos = n;
00135         return sum;
00136 }
00137 
00138 // parses T1 [, ..., Tn] optionally enclosed in brackets
00139 template <class T>
00140 int xconvert(const char* x, std::vector<T>& out, const char** errPos = 0, int sep = def_sep) {
00141         if (sep == 0) { sep = def_sep; }
00142         if (!x)       { return 0; }
00143         const char* n = x;
00144         int sum = 0;
00145         int ps  = 0;
00146         if (*n == '[') { ++ps; ++n; }
00147         for (;;) {
00148                 T temp;
00149                 int tok = xconvert(n, temp, &n, sep);
00150                 if (!tok) break;
00151                 ++sum;
00152                 out.push_back(temp);
00153                 if (!*n || *n != (char)sep) break;
00154                 n = n+1;
00155         }
00156         if (!ps || *n == ']') { n += ps; }
00157         else                  { while (sum) { out.pop_back(); --sum; } n = x; }
00158         if (errPos) *errPos = n;
00159         return sum;
00160 }
00161 
00162 // parses a sequence of up to maxTok Ts
00163 template <class T>
00164 int xconvert(const char* x, T* out, const char** errPos, int maxTok) {
00165         const char* n = x;
00166         int    sumTok = 0;
00167         while (maxTok) {
00168                 T temp;
00169                 int tok = xconvert(x, temp, &n, def_sep);
00170                 if (!tok) break;
00171                 ++sumTok; --maxTok;
00172                 *out++ = temp;
00173                 if (!*n || *n != (char)def_sep) break;
00174                 x = n+1;
00175         }
00176         if (errPos) *errPos = n;
00177         return sumTok;
00178 }
00180 // fall back parser
00182 template <class T>
00183 int xconvert(const char* x, T& out, const char** errPos, double) {
00184         std::size_t xLen = std::strlen(x);
00185         const char* err  = x;
00186         detail::input_stream<char> str(x, xLen);
00187         if (str >> out) {
00188                 if (str.eof()){ err += xLen; }
00189                 else          { err += static_cast<std::size_t>(str.tellg()); }
00190         }
00191         if (errPos) { *errPos = err; }
00192         return int(err != x);
00193 }
00195 // string -> T
00197 class bad_string_cast : public std::bad_cast {
00198 public:
00199         ~bad_string_cast() throw();
00200         virtual const char* what() const throw();
00201 };
00202 template <class T>
00203 bool string_cast(const char* arg, T& to) {
00204         const char* end;
00205         return xconvert(arg, to, &end, 0) != 0 && !*end;
00206 }
00207 template <class T>
00208 T string_cast(const char* s) {
00209         T to;
00210         if (string_cast<T>(s, to)) { return to; }
00211         throw bad_string_cast();
00212 }
00213 template <class T>
00214 T string_cast(const std::string& s) { return string_cast<T>(s.c_str()); }
00215 template <class T>
00216 bool string_cast(const std::string& from, T& to) { return string_cast<T>(from.c_str(), to); }
00217 }
00218 
00219 #endif
00220 


clasp
Author(s): Benjamin Kaufmann
autogenerated on Thu Aug 27 2015 12:41:40