1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <limits> 20 #include <sstream> 21 #include <string> 22 #include <vector> 23 #include <stdint.h> 24 #include <cmath> 25 26 namespace android 27 { 28 29 namespace utilities 30 { 31 32 /** 33 * Convert a given source type to a given destination type. 34 * 35 * String conversion to T reads the value of the type T in the given string. 36 * The function does not allow to have white spaces around the value to parse 37 * and tries to parse the whole string, which means that if some bytes were not 38 * read in the string, the function fails. 39 * Hexadecimal representation (ie. numbers starting with 0x) is supported only 40 * for integral types conversions. 41 * 42 * Numeric conversion to string formats the source value to decimal space. 43 * 44 * Vector to vector conversion calls convertTo on each element. 45 * 46 * @tparam srcType source type, default value is string type 47 * @tparam dstType destination type 48 * @param[in] input The source to convert from. 49 * @param[out] result Converted value if success, undefined on failure. 50 * 51 * @return true if conversion was successful, false otherwise. 52 */ 53 template <typename srcType, typename dstType> 54 static inline bool convertTo(const srcType &input, dstType &result); 55 56 /* details namespace is here to hide implementation details to header end user. It 57 * is NOT intended to be used outside. */ 58 namespace details 59 { 60 61 /** Helper class to limit instantiation of templates */ 62 template <typename T> 63 struct ConversionFromStringAllowed; 64 template <typename T> 65 struct ConversionToStringAllowed; 66 67 /* List of allowed types for conversion */ 68 template <> 69 struct ConversionFromStringAllowed<bool> {}; 70 template <> 71 struct ConversionFromStringAllowed<uint64_t> {}; 72 template <> 73 struct ConversionFromStringAllowed<int64_t> {}; 74 template <> 75 struct ConversionFromStringAllowed<uint32_t> {}; 76 template <> 77 struct ConversionFromStringAllowed<int32_t> {}; 78 template <> 79 struct ConversionFromStringAllowed<uint16_t> {}; 80 template <> 81 struct ConversionFromStringAllowed<int16_t> {}; 82 template <> 83 struct ConversionFromStringAllowed<float> {}; 84 template <> 85 struct ConversionFromStringAllowed<double> {}; 86 87 template <> 88 struct ConversionToStringAllowed<int64_t> {}; 89 template <> 90 struct ConversionToStringAllowed<uint64_t> {}; 91 template <> 92 struct ConversionToStringAllowed<uint32_t> {}; 93 template <> 94 struct ConversionToStringAllowed<int32_t> {}; 95 template <> 96 struct ConversionToStringAllowed<double> {}; 97 template <> 98 struct ConversionToStringAllowed<float> {}; 99 100 /** 101 * Set the decimal precision to 10 digits. 102 * Note that this setting is aligned with Android Audio Parameter 103 * policy concerning float storage into string. 104 */ 105 static const uint32_t gFloatPrecision = 10; 106 107 template <typename T> 108 static inline bool fromString(const std::string &str, T &result) 109 { 110 /* Check that conversion to that type is allowed. 111 * If this fails, this means that this template was not intended to be used 112 * with this type, thus that the result is undefined. */ 113 ConversionFromStringAllowed<T>(); 114 115 if (str.find_first_of(std::string("\r\n\t\v ")) != std::string::npos) { 116 return false; 117 } 118 119 /* Check for a '-' in string. If type is unsigned and a - is found, the 120 * parsing fails. This is made necessary because "-1" is read as 65535 for 121 * uint16_t, for example */ 122 if (str.find('-') != std::string::npos 123 && !std::numeric_limits<T>::is_signed) { 124 return false; 125 } 126 127 std::stringstream ss(str); 128 129 /* Sadly, the stream conversion does not handle hexadecimal format, thus 130 * check is done manually */ 131 if (str.substr(0, 2) == "0x") { 132 if (std::numeric_limits<T>::is_integer) { 133 ss >> std::hex >> result; 134 } else { 135 /* Conversion undefined for non integers */ 136 return false; 137 } 138 } else { 139 ss >> result; 140 } 141 142 return ss.eof() && !ss.fail() && !ss.bad(); 143 } 144 145 template <typename T> 146 static inline bool toString(const T &value, std::string &str) 147 { 148 /* Check that conversion from that type is allowed. 149 * If this fails, this means that this template was not intended to be used 150 * with this type, thus that the result is undefined. */ 151 ConversionToStringAllowed<T>(); 152 153 std::stringstream oss; 154 oss.precision(gFloatPrecision); 155 oss << value; 156 str = oss.str(); 157 return !oss.fail() && !oss.bad(); 158 } 159 160 template <typename srcType, typename dstType> 161 class Converter; 162 163 template <typename dstType> 164 class Converter<std::string, dstType> 165 { 166 public: 167 static inline bool run(const std::string &str, dstType &result) 168 { 169 return fromString<dstType>(str, result); 170 } 171 }; 172 173 template <typename srcType> 174 class Converter<srcType, std::string> 175 { 176 public: 177 static inline bool run(const srcType &str, std::string &result) 178 { 179 return toString<srcType>(str, result); 180 } 181 }; 182 183 /** Convert a vector by applying convertTo on each element. 184 * 185 * @tparam SrcElem Type of the src elements. 186 * @tparam DstElem Type of the destination elements. 187 */ 188 template <typename SrcElem, typename DstElem> 189 class Converter<std::vector<SrcElem>, std::vector<DstElem> > 190 { 191 public: 192 typedef const std::vector<SrcElem> Src; 193 typedef std::vector<DstElem> Dst; 194 195 static inline bool run(Src &src, Dst &dst) 196 { 197 typedef typename Src::const_iterator SrcIt; 198 dst.clear(); 199 dst.reserve(src.size()); 200 for (SrcIt it = src.begin(); it != src.end(); ++it) { 201 DstElem dstElem; 202 if (not convertTo(*it, dstElem)) { 203 return false; 204 } 205 dst.push_back(dstElem); 206 } 207 return true; 208 } 209 }; 210 211 } // namespace details 212 213 template <typename srcType, typename dstType> 214 static inline bool convertTo(const srcType &input, dstType &result) 215 { 216 return details::Converter<srcType, dstType>::run(input, result); 217 } 218 219 /** 220 * Specialization for int16_t of convertTo template function. 221 * 222 * This function follows the same paradigm than it's generic version. 223 * 224 * The specific implementation is made necessary because the stlport version of 225 * string streams is bugged and does not fail when giving overflowed values. 226 * This specialisation can be safely removed when stlport behaviour is fixed. 227 * 228 * @param[in] str the string to parse. 229 * @param[out] result reference to object where to store the result. 230 * 231 * @return true if conversion was successful, false otherwise. 232 */ 233 template <> 234 inline bool convertTo<std::string, int16_t>(const std::string &str, int16_t &result) 235 { 236 int64_t res; 237 238 if (!convertTo<std::string, int64_t>(str, res)) { 239 return false; 240 } 241 242 if (res > std::numeric_limits<int16_t>::max() || res < std::numeric_limits<int16_t>::min()) { 243 return false; 244 } 245 246 result = static_cast<int16_t>(res); 247 return true; 248 } 249 250 /** 251 * Specialization for float of convertTo template function. 252 * 253 * This function follows the same paradigm than it's generic version and is 254 * based on it but makes furthers checks on the returned value. 255 * 256 * The specific implementation is made necessary because the stlport conversion 257 * from string to float behaves differently than GNU STL: overflow produce 258 * +/-Infinity rather than an error. 259 * 260 * @param[in] str the string to parse. 261 * @param[out] result reference to object where to store the result. 262 * 263 * @return true if conversion was successful, false otherwise. 264 */ 265 template <> 266 inline bool convertTo<std::string, float>(const std::string &str, float &result) 267 { 268 if (!details::Converter<std::string, float>::run(str, result)) { 269 return false; 270 } 271 272 if (std::abs(result) == std::numeric_limits<float>::infinity() || 273 result == std::numeric_limits<float>::quiet_NaN()) { 274 return false; 275 } 276 277 return true; 278 } 279 280 /** 281 * Specialization for double of convertTo template function. 282 * 283 * This function follows the same paradigm than it's generic version and is 284 * based on it but makes furthers checks on the returned value. 285 * 286 * The specific implementation is made necessary because the stlport conversion 287 * from string to double behaves differently than GNU STL: overflow produce 288 * +/-Infinity rather than an error. 289 * 290 * @param[in] str the string to parse. 291 * @param[out] result reference to object where to store the result. 292 * 293 * @return true if conversion was successful, false otherwise. 294 */ 295 template <> 296 inline bool convertTo<std::string, double>(const std::string &str, double &result) 297 { 298 if (!details::Converter<std::string, double>::run(str, result)) { 299 return false; 300 } 301 302 if (std::abs(result) == std::numeric_limits<double>::infinity() || 303 result == std::numeric_limits<double>::quiet_NaN()) { 304 return false; 305 } 306 307 return true; 308 } 309 310 /** 311 * Specialization for boolean of convertTo template function. 312 * 313 * This function follows the same paradigm than it's generic version. 314 * This function accepts to parse boolean as "0/1" or "false/true" or 315 * "FALSE/TRUE". 316 * The specific implementation is made necessary because the behaviour of 317 * string streams when parsing boolean values is not sufficient to fit our 318 * requirements. Indeed, parsing "true" will correctly parse the value, but the 319 * end of stream is not reached which makes the ss.eof() fails in the generic 320 * implementation. 321 * 322 * @param[in] str the string to parse. 323 * @param[out] result reference to object where to store the result. 324 * 325 * @return true if conversion was successful, false otherwise. 326 */ 327 template <> 328 inline bool convertTo<std::string, bool>(const std::string &str, bool &result) 329 { 330 if (str == "0" || str == "FALSE" || str == "false") { 331 result = false; 332 return true; 333 } 334 335 if (str == "1" || str == "TRUE" || str == "true") { 336 result = true; 337 return true; 338 } 339 340 return false; 341 } 342 343 /** 344 * Specialization for boolean to string of convertTo template function. 345 * 346 * This function follows the same paradigm than it's generic version. 347 * This function arbitrarily decides to return "false/true". 348 * It is compatible with the specialization from string to boolean. 349 * 350 * @param[in] isSet boolean to convert to a string. 351 * @param[out] result reference to object where to store the result. 352 * 353 * @return true if conversion was successful, false otherwise. 354 */ 355 template <> 356 inline bool convertTo<bool, std::string>(const bool &isSet, std::string &result) 357 { 358 result = isSet ? "true" : "false"; 359 return true; 360 } 361 362 /** 363 * Specialization for string to string of convertTo template function. 364 * 365 * This function is a dummy conversion from string to string. 366 * In case of clients using template as well, this implementation avoids adding extra 367 * specialization to bypass the conversion from string to string. 368 * 369 * @param[in] str the string to parse. 370 * @param[out] result reference to object where to store the result. 371 * 372 * @return true if conversion was successful, false otherwise. 373 */ 374 template <> 375 inline bool convertTo<std::string, std::string>(const std::string &str, std::string &result) 376 { 377 result = str; 378 return true; 379 } 380 381 } // namespace utilities 382 383 } // namespace android 384