1 /* 2 * Copyright (c) 2011-2014, Intel Corporation 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, 6 * are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation and/or 13 * other materials provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its contributors 16 * may be used to endorse or promote products derived from this software without 17 * specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #pragma once 32 33 #include <limits> 34 #include <sstream> 35 #include <string> 36 #include <stdint.h> 37 #include <cmath> 38 #include <type_traits> 39 40 /* details namespace is here to hide implementation details to header end user. It 41 * is NOT intended to be used outside. */ 42 namespace details 43 { 44 45 /* List of allowed types for conversion */ 46 template <typename T> 47 struct ConvertionAllowed : std::false_type 48 { 49 }; 50 template <> 51 struct ConvertionAllowed<bool> : std::true_type 52 { 53 }; 54 template <> 55 struct ConvertionAllowed<long long> : std::true_type 56 { 57 }; 58 template <> 59 struct ConvertionAllowed<unsigned long long> : std::true_type 60 { 61 }; 62 template <> 63 struct ConvertionAllowed<long> : std::true_type 64 { 65 }; 66 template <> 67 struct ConvertionAllowed<unsigned long> : std::true_type 68 { 69 }; 70 template <> 71 struct ConvertionAllowed<int> : std::true_type 72 { 73 }; 74 template <> 75 struct ConvertionAllowed<unsigned int> : std::true_type 76 { 77 }; 78 template <> 79 struct ConvertionAllowed<short> : std::true_type 80 { 81 }; 82 template <> 83 struct ConvertionAllowed<unsigned short> : std::true_type 84 { 85 }; 86 template <> 87 struct ConvertionAllowed<unsigned char> : std::true_type 88 { 89 }; 90 template <> 91 struct ConvertionAllowed<signed char> : std::true_type 92 { 93 }; 94 template <> 95 struct ConvertionAllowed<float> : std::true_type 96 { 97 }; 98 template <> 99 struct ConvertionAllowed<double> : std::true_type 100 { 101 }; 102 103 /* Allow chars and unsigned chars to be converted via integers */ 104 template <typename T, typename Via> 105 struct ConvertionAllowedVia : std::false_type 106 { 107 }; 108 template <> 109 struct ConvertionAllowedVia<unsigned char, unsigned int> : std::true_type 110 { 111 }; 112 template <> 113 struct ConvertionAllowedVia<signed char, int> : std::true_type 114 { 115 }; 116 117 template <typename T> 118 static inline bool convertTo(const std::string &str, T &result) 119 { 120 /* Check that conversion to that type is allowed. 121 * If this fails, this means that this template was not intended to be used 122 * with this type, thus that the result is undefined. */ 123 static_assert(ConvertionAllowed<T>::value, "convertTo does not support this conversion"); 124 125 if (str.find_first_of(std::string("\r\n\t\v ")) != std::string::npos) { 126 return false; 127 } 128 129 /* Check for a '-' in string. If type is unsigned and a - is found, the 130 * parsing fails. This is made necessary because "-1" is read as 65535 for 131 * uint16_t, for example */ 132 if (str.find("-") != std::string::npos && !std::numeric_limits<T>::is_signed) { 133 return false; 134 } 135 136 std::stringstream ss(str); 137 138 /* Sadly, the stream conversion does not handle hexadecimal format, thus 139 * check is done manually */ 140 if (str.substr(0, 2) == "0x") { 141 if (std::numeric_limits<T>::is_integer) { 142 ss >> std::hex >> result; 143 } else { 144 /* Conversion undefined for non integers */ 145 return false; 146 } 147 } else { 148 ss >> result; 149 } 150 151 return ss.eof() && !ss.fail() && !ss.bad(); 152 } 153 154 template <typename T, typename Via> 155 static inline bool convertToVia(const std::string &str, T &result) 156 { 157 /* Check that conversion to that type is allowed. 158 * If this fails, this means that this template was not intended to be used 159 * with this type, thus that the result is undefined. */ 160 static_assert(ConvertionAllowedVia<T, Via>::value, 161 "convertToVia does not support this conversion"); 162 163 /* We want to override the behaviour of convertTo<T> with that of 164 * convertTo<Via> and then safely cast the result into a T. */ 165 Via res; 166 167 if (!convertTo<Via>(str, res)) { 168 return false; 169 } 170 171 if ((res > std::numeric_limits<T>::max()) or (res < std::numeric_limits<T>::min())) { 172 return false; 173 } 174 175 result = static_cast<T>(res); 176 return true; 177 } 178 } // namespace details 179 180 /** 181 * Convert a string to a given type. 182 * 183 * This template function read the value of the type T in the given string. 184 * The function does not allow to have white spaces around the value to parse 185 * and tries to parse the whole string, which means that if some bytes were not 186 * read in the string, the function fails. 187 * Hexadecimal representation (ie numbers starting with 0x) is supported only 188 * for integral types conversions. 189 * Result may be modified, even in case of failure. 190 * 191 * @param[in] str the string to parse. 192 * @param[out] result reference to object where to store the result. 193 * 194 * @return true if conversion was successful, false otherwise. 195 */ 196 template <typename T> 197 static inline bool convertTo(const std::string &str, T &result) 198 { 199 return details::convertTo<T>(str, result); 200 } 201 202 /** Specialization for unsigned char of convertTo template function. 203 * 204 * This function follows the same paradigm than it's generic version. 205 * 206 * The generic version was converting char as it was a character 207 * (unsigned char is an alias to unsigned char on most compiler). 208 * Thus converting "1" would return 49 ie '1'. 209 * As convertTo is thought as an _numerical_ convertion tool 210 * (contrary to boost::lexical_cast for example), 211 * forbid considering the input as a character and consider unsigned char 212 * (aka unsigned char) as a number exclusively. 213 * 214 * @param[in] str the string to parse. 215 * @param[out] result reference to object where to store the result. 216 * 217 * @return true if conversion was successful, false otherwise. 218 */ 219 template <> 220 inline bool convertTo<unsigned char>(const std::string &str, unsigned char &result) 221 { 222 return details::convertToVia<unsigned char, unsigned int>(str, result); 223 } 224 225 /** Specialization for signed char of convertTo template function. 226 * 227 * @see convertTo<unsigned char> 228 */ 229 template <> 230 inline bool convertTo<signed char>(const std::string &str, signed char &result) 231 { 232 return details::convertToVia<signed char, int>(str, result); 233 } 234 /** 235 * Specialization for float of convertTo template function. 236 * 237 * This function follows the same paradigm than it's generic version and is 238 * based on it but makes furthers checks on the returned value. 239 * 240 * The specific implementation is made necessary because the stlport conversion 241 * from string to float behaves differently than GNU STL: overflow produce 242 * +/-Infinity rather than an error. 243 * 244 * @param[in] str the string to parse. 245 * @param[out] result reference to object where to store the result. 246 * 247 * @return true if conversion was successful, false otherwise. 248 */ 249 template <> 250 inline bool convertTo<float>(const std::string &str, float &result) 251 { 252 if (!details::convertTo(str, result)) { 253 return false; 254 } 255 256 if (!std::isfinite(result)) { 257 return false; 258 } 259 260 return true; 261 } 262 263 /** 264 * Specialization for double of convertTo template function. 265 * 266 * This function follows the same paradigm than it's generic version and is 267 * based on it but makes furthers checks on the returned value. 268 * 269 * The specific implementation is made necessary because the stlport conversion 270 * from string to double behaves differently than GNU STL: overflow produce 271 * +/-Infinity rather than an error. 272 * 273 * @param[in] str the string to parse. 274 * @param[out] result reference to object where to store the result. 275 * 276 * @return true if conversion was successful, false otherwise. 277 */ 278 template <> 279 inline bool convertTo<double>(const std::string &str, double &result) 280 { 281 if (!details::convertTo(str, result)) { 282 return false; 283 } 284 285 if (!std::isfinite(result)) { 286 return false; 287 } 288 289 return true; 290 } 291 292 /** 293 * Specialization for boolean of convertTo template function. 294 * 295 * This function follows the same paradigm than it's generic version. 296 * This function accepts to parse boolean as "0/1" or "false/true" or 297 * "FALSE/TRUE". 298 * The specific implementation is made necessary because the behaviour of 299 * string streams when parsing boolean values is not sufficient to fit our 300 * requirements. Indeed, parsing "true" will correctly parse the value, but the 301 * end of stream is not reached which makes the ss.eof() fails in the generic 302 * implementation. 303 * 304 * @param[in] str the string to parse. 305 * @param[out] result reference to object where to store the result. 306 * 307 * @return true if conversion was successful, false otherwise. 308 */ 309 template <> 310 inline bool convertTo<bool>(const std::string &str, bool &result) 311 { 312 if (str == "0" || str == "FALSE" || str == "false") { 313 result = false; 314 return true; 315 } 316 317 if (str == "1" || str == "TRUE" || str == "true") { 318 result = true; 319 return true; 320 } 321 322 return false; 323 } 324