pelib
2.0.0
|
00001 /* 00002 Copyright 2015 Nicolas Melot 00003 00004 This file is part of Pelib. 00005 00006 Pelib is free software: you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation, either version 3 of the License, or 00009 (at your option) any later version. 00010 00011 Pelib is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with Pelib. If not, see <http://www.gnu.org/licenses/>. 00018 */ 00019 00020 00021 #include <iostream> 00022 #include <cstdlib> 00023 #include <fstream> 00024 #include <sstream> 00025 #include <string> 00026 #include <boost/regex.hpp> 00027 #include <iomanip> 00028 #include <boost/algorithm/string.hpp> 00029 00030 #include <pelib/ParseException.hpp> 00031 #include <pelib/NoDecimalFloatException.hpp> 00032 #include <pelib/Algebra.hpp> 00033 #include <pelib/AlgebraData.hpp> 00034 #include <pelib/DataParser.hpp> 00035 00036 #ifndef PELIB_ALGEBRADATAPARSER 00037 #define PELIB_ALGEBRADATAPARSER 00038 00039 namespace pelib 00040 { 00042 class AlgebraDataParser : public DataParser 00043 { 00044 public: 00046 template <class Target> 00047 static 00048 Target 00049 convert(std::string element, bool strict = 0) 00050 { 00051 Target out; 00052 bool infinity, positive; 00053 00054 if(is_integer(typeid(out)) || is_decimal(typeid(out))) 00055 { 00056 boost::algorithm::to_lower(element); 00057 if(element.compare("+inf") == 0 || element.compare("inf") == 0) 00058 { 00059 out = std::numeric_limits<Target>::max(); 00060 infinity = true; 00061 positive = true; 00062 } 00063 else 00064 { 00065 if(element.compare("-inf") == 0) 00066 { 00067 out = std::numeric_limits<Target>::min(); 00068 infinity = true; 00069 positive = false; 00070 } 00071 else 00072 { 00073 std::istringstream converter(element); 00074 converter >> out; 00075 infinity = false; 00076 00077 if(converter.fail()) 00078 { 00079 throw ParseException(std::string("Couln't convert literal \"").append(element).append("\" into type \"").append(typeid(out).name()).append("\".")); 00080 } 00081 00082 std::stringstream ss; 00083 ss << out; 00084 double val; 00085 ss >> val; 00086 00087 positive = val >= 0; 00088 } 00089 } 00090 } 00091 else 00092 { 00093 std::istringstream converter(element); 00094 converter >> out; 00095 00096 if(converter.fail()) 00097 { 00098 throw ParseException(std::string("Couln't convert literal \"").append(element).append("\" into type \"").append(typeid(out).name()).append("\".")); 00099 } 00100 00101 return out; 00102 } 00103 00104 #if TRACE 00105 std::cerr << "String element: \"" << element << "\"" << std::endl; 00106 std::cerr << "Strict checking: \"" << strict << "\"" << std::endl; 00107 std::cerr << "Let us proceed with optional checking" << std::endl; 00108 #endif 00109 if(strict) 00110 { 00111 #if TRACE 00112 std::cerr << "OK so we have to check" << std::endl; 00113 #endif 00114 // We asked a floating-point conversion, but provided a integer 00115 //if(strcmp(typeid(out).name(), "f") == 0 || strcmp(typeid(out).name(), "d") == 0) 00116 if(is_decimal(typeid(out)) && ! is_integer(typeid(out))) 00117 { 00118 #if TRACE 00119 std::cerr << "So we are asking for a decimal conversion" << std::endl; 00120 #endif 00121 // let's try to parse against a fixed-point value 00122 //match("[-+]?\\d+\\.\\d+", element); 00123 boost::cmatch match; 00124 if(!boost::regex_match(element.c_str(), match, boost::regex("[-+]?\\d+\\.\\d+"))) 00125 { 00126 #if TRACE 00127 // This should bin in the else clause 00128 //std::cerr << "\"" << element << "\" passed the fixed-point format matching" << std::endl; 00129 #endif 00130 // OK so it doesn't parse a fixed-point notation 00131 // Then I suppose it was a scientific notation; let's see if it indeed denotes a decimal digit 00132 double val; 00133 std::stringstream ss; 00134 ss << out; 00135 ss >> val; 00136 long long int int_test = (long long int)floor(val); 00137 //std::istringstream converter(element); 00138 //converter >> int_test; 00139 00140 #if TRACE 00141 std::cerr << "\"" << element << "\" is not at fixed-point format, may be scientific notation" << std::endl; 00142 #endif 00143 00144 if(int_test == val && !infinity) 00145 { 00146 // Integer-converted and floating-point were equal, then it was an integer, you fool 00147 #if TRACE 00148 std::cerr << "The decimal part of \"" << element << "\" is nul, therefore we have an integer" << std::endl; 00149 #endif 00150 throw NoDecimalFloatException(std::string("Asked a decimal conversion, but \"").append(element).append("\" is integer."), val); 00151 } 00152 00153 if(infinity && std::numeric_limits<Target>::has_infinity) 00154 { 00155 ss.str(""); 00156 ss.clear(); // Clear state flags. 00157 ss << std::numeric_limits<Target>::infinity(); 00158 ss >> val; 00159 00160 ss.str(""); 00161 ss.clear(); 00162 ss << (positive ? val : -1 * val); 00163 ss >> out; 00164 } 00165 #if TRACE 00166 std::cerr << "Passed the scientific format matching" << std::endl; 00167 #endif 00168 } 00169 #if TRACE 00170 std::cerr << "OK I valid this conversion" << std::endl; 00171 #endif 00172 } 00173 00174 // We asked an integer conversion, but provided a float 00175 //if(strcmp(typeid(out).name(), "f") != 0 && strcmp(typeid(out).name(), "d") != 0) 00176 if(! is_decimal(typeid(out)) && is_integer(typeid(out))) 00177 { 00178 #if TRACE 00179 std::cerr << "So we are asking for a integer conversion" << std::endl; 00180 #endif 00181 // let's try to parse against a fixed-point value 00182 //match("[+-]?\\d+\\.\\d+", element); 00183 boost::cmatch match; 00184 if(!boost::regex_match(element.c_str(), match, boost::regex("[+-]?\\d+\\.\\d+"))) 00185 { 00186 #if TRACE 00187 std::cerr << "It is not fixed-point format, good" << std::endl; 00188 #endif 00189 // Then I suppose it was a scientific notation; let's see if it indeed denotes an integer digit 00190 if(!infinity) 00191 { 00192 double int_test; 00193 std::istringstream converter(element); 00194 converter >> int_test; 00195 00196 long long int val; 00197 std::stringstream ss; 00198 ss << out; 00199 ss >> val; 00200 00201 if(int_test != val) 00202 { 00203 #if TRACE 00204 std::cerr << "But this is not an integer anyway" << std::endl; 00205 #endif 00206 // Integer-converted and floating-point were equal, then it was an integer, you fool 00207 throw ParseException(std::string("Asked an integer conversion, but \"").append(element).append("\" is decimal.")); 00208 } 00209 #if TRACE 00210 std::cerr << "OK I valid this conversion" << std::endl; 00211 #endif 00212 return out; 00213 } 00214 else 00215 { 00216 if(infinity && std::numeric_limits<Target>::has_infinity) 00217 { 00218 long long int val; 00219 std::stringstream ss; 00220 ss << std::numeric_limits<Target>::infinity(); 00221 ss >> val; 00222 00223 ss.str(""); 00224 ss.clear(); 00225 ss << (positive ? val : -1 * val); 00226 ss >> out; 00227 00228 return out; 00229 } 00230 else 00231 { 00232 return out; 00233 } 00234 } 00235 } 00236 #if TRACE 00237 std::cerr << "But element was fixed-point format" << std::endl; 00238 #endif 00239 throw ParseException(std::string("Asked an integer conversion, but \"").append(element).append("\" is decimal.")); 00240 } 00241 } 00242 else 00243 { 00244 if(infinity && std::numeric_limits<Target>::has_infinity) 00245 { 00246 std::stringstream ss; 00247 00248 if(is_decimal(typeid(out))) 00249 { 00250 long double val; 00251 ss << std::numeric_limits<Target>::infinity(); 00252 ss >> val; 00253 ss.str(""); 00254 ss.clear(); 00255 ss << (positive ? val : -1 * val); 00256 } 00257 else 00258 { 00259 long long int val; 00260 ss << std::numeric_limits<Target>::infinity(); 00261 ss >> val; 00262 ss.str(""); 00263 ss.clear(); 00264 ss << (positive ? val : -1 * val); 00265 } 00266 00267 ss >> out; 00268 return out; 00269 } 00270 else 00271 { 00272 return out; 00273 } 00274 } 00275 00276 return out; 00277 } 00278 00279 // This is causing too much problem, probably due to a bug in boost::regex, even when inlining 00280 // Inline manually instead 00281 #if 0 00282 00283 static inline 00284 boost::cmatch 00285 match(std::string regex, std::string str); 00286 #endif 00287 00289 virtual 00290 std::string 00291 getDetailedPattern() = 0; 00292 00294 virtual 00295 std::string 00296 getGlobalPattern() = 0; 00297 00299 virtual 00300 AlgebraData* 00301 parse(std::istream &in) = 0; 00302 protected: 00303 static bool is_decimal(const std::type_info &var) 00304 { 00305 return (std::string(var.name()).compare(std::string(typeid(float).name())) == 0) || 00306 (std::string(var.name()).compare(std::string(typeid(double).name())) == 0) || 00307 (std::string(var.name()).compare(std::string(typeid(long double).name())) == 0); 00308 } 00309 00310 static bool is_integer(const std::type_info &var) 00311 { 00312 /* 00313 List obtained by running the following C program 00314 #include <iostream> 00315 #include <cstdlib> 00316 #include <typeinfo> 00317 00318 using namespace std; 00319 00320 #define show(type) cout << #type << " " << typeid(type).name() << endl; 00321 00322 int 00323 main(int argc, char **argv) 00324 { 00325 show(int); 00326 show(unsigned int); 00327 show(long int); 00328 show(long unsigned int); 00329 show(long long int); 00330 show(long long unsigned int); 00331 cout << endl; 00332 show(size_t); 00333 show(ptrdiff_t); 00334 show(signed size_t); 00335 show(unsigned ptrdiff_t); 00336 show(long size_t); 00337 show(long long size_t); 00338 show(long ptrdiff_t); 00339 show(long long ptrdiff_t); 00340 cout << endl; 00341 show(float); 00342 show(double); 00343 show(long double); 00344 return EXIT_SUCCESS; 00345 } 00346 00347 ./test | rev | sort -k 1 | uniq -w 1 | cut -f 1 -d ' ' --complement | rev 00348 */ 00349 00350 return (std::string(var.name()).compare(std::string(typeid(int).name())) == 0) || 00351 (std::string(var.name()).compare(std::string(typeid(unsigned int).name())) == 0) || 00352 (std::string(var.name()).compare(std::string(typeid(long size_t).name())) == 0) || 00353 (std::string(var.name()).compare(std::string(typeid(size_t).name())) == 0) || 00354 (std::string(var.name()).compare(std::string(typeid(long long size_t).name())) == 0) || 00355 (std::string(var.name()).compare(std::string(typeid(long long unsigned int).name())) == 0); 00356 } 00357 private: 00358 // Nothing private 00359 }; 00360 } 00361 00362 #endif