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 39/* details namespace is here to hide implementation details to header end user. It 40 * is NOT intended to be used outside. */ 41namespace details 42{ 43 44/** Helper class to limit instantiation of templates */ 45template<typename T> 46struct ConvertionAllowed; 47 48/* List of allowed types for conversion */ 49template<> struct ConvertionAllowed<bool> {}; 50template<> struct ConvertionAllowed<uint64_t> {}; 51template<> struct ConvertionAllowed<int64_t> {}; 52template<> struct ConvertionAllowed<uint32_t> {}; 53template<> struct ConvertionAllowed<int32_t> {}; 54template<> struct ConvertionAllowed<uint16_t> {}; 55template<> struct ConvertionAllowed<int16_t> {}; 56template<> struct ConvertionAllowed<float> {}; 57template<> struct ConvertionAllowed<double> {}; 58 59template<typename T> 60static inline bool convertTo(const std::string &str, T &result) 61{ 62 /* Check that conversion to that type is allowed. 63 * If this fails, this means that this template was not intended to be used 64 * with this type, thus that the result is undefined. */ 65 ConvertionAllowed<T>(); 66 67 if (str.find_first_of(std::string("\r\n\t\v ")) != std::string::npos) { 68 return false; 69 } 70 71 /* Check for a '-' in string. If type is unsigned and a - is found, the 72 * parsing fails. This is made necessary because "-1" is read as 65535 for 73 * uint16_t, for example */ 74 if (str.find("-") != std::string::npos 75 && !std::numeric_limits<T>::is_signed) { 76 return false; 77 } 78 79 std::stringstream ss(str); 80 81 /* Sadly, the stream conversion does not handle hexadecimal format, thus 82 * check is done manually */ 83 if (str.substr(0, 2) == "0x") { 84 if (std::numeric_limits<T>::is_integer) { 85 ss >> std::hex >> result; 86 } 87 else { 88 /* Conversion undefined for non integers */ 89 return false; 90 } 91 } else { 92 ss >> result; 93 } 94 95 return ss.eof() && !ss.fail() && !ss.bad(); 96} 97} // namespace details 98 99/** 100 * Convert a string to a given type. 101 * 102 * This template function read the value of the type T in the given string. 103 * The function does not allow to have white spaces around the value to parse 104 * and tries to parse the whole string, which means that if some bytes were not 105 * read in the string, the function fails. 106 * Hexadecimal representation (ie numbers starting with 0x) is supported only 107 * for integral types conversions. 108 * Result may be modified, even in case of failure. 109 * 110 * @param[in] str the string to parse. 111 * @param[out] result reference to object where to store the result. 112 * 113 * @return true if conversion was successful, false otherwise. 114 */ 115template<typename T> 116static inline bool convertTo(const std::string &str, T &result) 117{ 118 return details::convertTo<T>(str, result); 119} 120 121/** 122 * Specialization for int16_t of convertTo template function. 123 * 124 * This function follows the same paradigm than it's generic version. 125 * 126 * The specific implementation is made necessary because the stlport version of 127 * string streams is bugged and does not fail when giving overflowed values. 128 * This specialisation can be safely removed when stlport behaviour is fixed. 129 * 130 * @param[in] str the string to parse. 131 * @param[out] result reference to object where to store the result. 132 * 133 * @return true if conversion was successful, false otherwise. 134 */ 135template<> 136inline bool convertTo<int16_t>(const std::string &str, int16_t &result) 137{ 138 int64_t res; 139 140 if (!convertTo<int64_t>(str, res)) { 141 return false; 142 } 143 144 if (res > std::numeric_limits<int16_t>::max() || res < std::numeric_limits<int16_t>::min()) { 145 return false; 146 } 147 148 result = static_cast<int16_t>(res); 149 return true; 150} 151 152/** 153 * Specialization for float of convertTo template function. 154 * 155 * This function follows the same paradigm than it's generic version and is 156 * based on it but makes furthers checks on the returned value. 157 * 158 * The specific implementation is made necessary because the stlport conversion 159 * from string to float behaves differently than GNU STL: overflow produce 160 * +/-Infinity rather than an error. 161 * 162 * @param[in] str the string to parse. 163 * @param[out] result reference to object where to store the result. 164 * 165 * @return true if conversion was successful, false otherwise. 166 */ 167template<> 168inline bool convertTo<float>(const std::string &str, float &result) 169{ 170 if (!details::convertTo(str, result)) { 171 return false; 172 } 173 174 if (std::abs(result) == std::numeric_limits<float>::infinity() || 175 result == std::numeric_limits<float>::quiet_NaN()) { 176 return false; 177 } 178 179 return true; 180} 181 182/** 183 * Specialization for double of convertTo template function. 184 * 185 * This function follows the same paradigm than it's generic version and is 186 * based on it but makes furthers checks on the returned value. 187 * 188 * The specific implementation is made necessary because the stlport conversion 189 * from string to double behaves differently than GNU STL: overflow produce 190 * +/-Infinity rather than an error. 191 * 192 * @param[in] str the string to parse. 193 * @param[out] result reference to object where to store the result. 194 * 195 * @return true if conversion was successful, false otherwise. 196 */ 197template<> 198inline bool convertTo<double>(const std::string &str, double &result) 199{ 200 if (!details::convertTo(str, result)) { 201 return false; 202 } 203 204 if (std::abs(result) == std::numeric_limits<double>::infinity() || 205 result == std::numeric_limits<double>::quiet_NaN()) { 206 return false; 207 } 208 209 return true; 210} 211 212/** 213 * Specialization for boolean of convertTo template function. 214 * 215 * This function follows the same paradigm than it's generic version. 216 * This function accepts to parse boolean as "0/1" or "false/true" or 217 * "FALSE/TRUE". 218 * The specific implementation is made necessary because the behaviour of 219 * string streams when parsing boolean values is not sufficient to fit our 220 * requirements. Indeed, parsing "true" will correctly parse the value, but the 221 * end of stream is not reached which makes the ss.eof() fails in the generic 222 * implementation. 223 * 224 * @param[in] str the string to parse. 225 * @param[out] result reference to object where to store the result. 226 * 227 * @return true if conversion was successful, false otherwise. 228 */ 229template<> 230inline bool convertTo<bool>(const std::string &str, bool &result) 231{ 232 if (str == "0" || str == "FALSE" || str == "false") { 233 result = false; 234 return true; 235 } 236 237 if (str == "1" || str == "TRUE" || str == "true") { 238 result = true; 239 return true; 240 } 241 242 return false; 243} 244