Home | History | Annotate | Download | only in media
      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