From c634daef6a9de8df7245d4fb6fbbcdf0ad7ac7ff Mon Sep 17 00:00:00 2001 From: Tim Mayberry Date: Mon, 3 Aug 2015 12:32:31 +1000 Subject: Add locale independent and thread safe string conversion API with tests All conversions are performed as if in the "C" locale but without actually changing locale. This is a wrapper around printf/sscanf for int types which aren't affected by locale and uses glib functions g_ascii_strtod and g_ascii_dtostr for float/double types. My first attempt at this used std::stringstream and ios::imbue(std::locale::classic()) as it should be thread safe, but testing shows it is not for gcc/mingw-w64 on Windows, and possibly also some versions of macOS/OS X. Use "yes" and "no" when converting a boolean in PBD::string_to as this seems to be the convention used throughout libardour which will allow using string_to in those cases. Add accepted bool string values from PBD::string_is_affirmative to PBD::string_to Mark strings in pbd/string_convert.cc as not for translation Add u/int16_t string conversions to pbd/string_convert.h and tests Add DEBUG_TRACE output on conversion errors Add int8_t/uint8_t conversions(using int16/uint16 types) to string_convert.h Add support for converting an infinity expression to/from string Follows the C99/C11 standard for strtof/strtod where subject sequence is an optional plus or minus sign then INF or INFINITY, ignoring case. --- libs/pbd/pbd/string_convert.h | 430 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 430 insertions(+) create mode 100644 libs/pbd/pbd/string_convert.h (limited to 'libs/pbd/pbd/string_convert.h') diff --git a/libs/pbd/pbd/string_convert.h b/libs/pbd/pbd/string_convert.h new file mode 100644 index 0000000000..3194c48863 --- /dev/null +++ b/libs/pbd/pbd/string_convert.h @@ -0,0 +1,430 @@ +/* + Copyright (C) 2015 Tim Mayberry + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef PBD_STRING_CONVERT_H +#define PBD_STRING_CONVERT_H + +#include +#include + +#include "pbd/libpbd_visibility.h" + +/** + * Locale independent and thread-safe string conversion utility functions. + * + * All conversions are done as if they were performed in the C locale without + * actually changing the current locale. + */ +namespace PBD { + +LIBPBD_API bool bool_to_string (bool val, std::string& str); + +LIBPBD_API bool int16_to_string (int16_t val, std::string& str); + +LIBPBD_API bool uint16_to_string (uint16_t val, std::string& str); + +LIBPBD_API bool int32_to_string (int32_t val, std::string& str); + +LIBPBD_API bool uint32_to_string (uint32_t val, std::string& str); + +LIBPBD_API bool int64_to_string (int64_t val, std::string& str); + +LIBPBD_API bool uint64_to_string (uint64_t val, std::string& str); + +LIBPBD_API bool float_to_string (float val, std::string& str); + +LIBPBD_API bool double_to_string (double val, std::string& str); + +LIBPBD_API bool string_to_bool (const std::string& str, bool& val); + +LIBPBD_API bool string_to_int16 (const std::string& str, int16_t& val); + +LIBPBD_API bool string_to_uint16 (const std::string& str, uint16_t& val); + +LIBPBD_API bool string_to_int32 (const std::string& str, int32_t& val); + +LIBPBD_API bool string_to_uint32 (const std::string& str, uint32_t& val); + +LIBPBD_API bool string_to_int64 (const std::string& str, int64_t& val); + +LIBPBD_API bool string_to_uint64 (const std::string& str, uint64_t& val); + +LIBPBD_API bool string_to_float (const std::string& str, float& val); + +LIBPBD_API bool string_to_double (const std::string& str, double& val); + +template +inline bool to_string (T val, std::string& str) +{ + // This will cause a compile time error if this function is ever + // instantiated, which is useful to catch unintended conversions + typename T::TO_STRING_TEMPLATE_NOT_DEFINED_FOR_THIS_TYPE invalid_type; + return false; +} + +template +inline bool to_string (bool val, std::string& str) +{ + return bool_to_string (val, str); +} + +template +inline bool to_string (int8_t val, std::string& str) +{ + return int16_to_string (val, str); +} + +template +inline bool to_string (uint8_t val, std::string& str) +{ + return uint16_to_string (val, str); +} + +template +inline bool to_string (int16_t val, std::string& str) +{ + return int16_to_string (val, str); +} + +template +inline bool to_string (uint16_t val, std::string& str) +{ + return uint16_to_string (val, str); +} + +template +inline bool to_string (int32_t val, std::string& str) +{ + return int32_to_string (val, str); +} + +template +inline bool to_string (uint32_t val, std::string& str) +{ + return uint32_to_string (val, str); +} + +template +inline bool to_string (int64_t val, std::string& str) +{ + return int64_to_string (val, str); +} + +template +inline bool to_string (uint64_t val, std::string& str) +{ + return uint64_to_string (val, str); +} + +template +inline bool to_string (float val, std::string& str) +{ + return float_to_string (val, str); +} + +template +inline bool to_string (double val, std::string& str) +{ + return double_to_string (val, str); +} + +template +inline bool string_to (const std::string& str, T& val) +{ + // This will cause a compile time error if this function is ever + // instantiated, which is useful to catch unintended conversions + typename T::TO_STRING_TEMPLATE_NOT_DEFINED_FOR_THIS_TYPE invalid_type; + return false; +} + +template +inline bool string_to (const std::string& str, bool& val) +{ + return string_to_bool (str, val); +} + +template +inline bool string_to (const std::string& str, int8_t& val) +{ + int16_t tmp = val; + bool success = string_to_int16 (str, tmp); + if (!success) return false; + val = tmp; + return true; +} + +template +inline bool string_to (const std::string& str, uint8_t& val) +{ + uint16_t tmp = val; + bool success = string_to_uint16 (str, tmp); + if (!success) return false; + val = tmp; + return true; +} + +template +inline bool string_to (const std::string& str, int16_t& val) +{ + return string_to_int16 (str, val); +} + +template +inline bool string_to (const std::string& str, uint16_t& val) +{ + return string_to_uint16 (str, val); +} + +template +inline bool string_to (const std::string& str, int32_t& val) +{ + return string_to_int32 (str, val); +} + +template +inline bool string_to (const std::string& str, uint32_t& val) +{ + return string_to_uint32 (str, val); +} + +template +inline bool string_to (const std::string& str, int64_t& val) +{ + return string_to_int64 (str, val); +} + +template +inline bool string_to (const std::string& str, uint64_t& val) +{ + return string_to_uint64 (str, val); +} + +template +inline bool string_to (const std::string& str, float& val) +{ + return string_to_float (str, val); +} + +template +inline bool string_to (const std::string& str, double& val) +{ + return string_to_double (str, val); +} + +//////////////////////////////////////////////////////////////// +// Variation that disregards conversion errors +//////////////////////////////////////////////////////////////// + +template +inline std::string to_string (T val) +{ + // This will cause a compile time error if this function is ever + // instantiated, which is useful to catch unintended conversions + typename T::TO_STRING_TEMPLATE_NOT_DEFINED_FOR_THIS_TYPE invalid_type; + return std::string(); +} + +template <> +inline std::string to_string (bool val) +{ + std::string tmp; + bool_to_string (val, tmp); + return tmp; +} + +template <> +inline std::string to_string (int8_t val) +{ + std::string tmp; + int16_to_string (val, tmp); + return tmp; +} + +template <> +inline std::string to_string (uint8_t val) +{ + std::string tmp; + uint16_to_string (val, tmp); + return tmp; +} + +template <> +inline std::string to_string (int16_t val) +{ + std::string tmp; + int16_to_string (val, tmp); + return tmp; +} + +template <> +inline std::string to_string (uint16_t val) +{ + std::string tmp; + uint16_to_string (val, tmp); + return tmp; +} + +template <> +inline std::string to_string (int32_t val) +{ + std::string tmp; + int32_to_string (val, tmp); + return tmp; +} + +template <> +inline std::string to_string (uint32_t val) +{ + std::string tmp; + uint32_to_string (val, tmp); + return tmp; +} + +template <> +inline std::string to_string (int64_t val) +{ + std::string tmp; + int64_to_string (val, tmp); + return tmp; +} + +template <> +inline std::string to_string (uint64_t val) +{ + std::string tmp; + uint64_to_string (val, tmp); + return tmp; +} + +template <> +inline std::string to_string (float val) +{ + std::string tmp; + float_to_string (val, tmp); + return tmp; +} + +template <> +inline std::string to_string (double val) +{ + std::string tmp; + double_to_string (val, tmp); + return tmp; +} + +template +inline T string_to (const std::string& str) +{ + // This will cause a compile time error if this function is ever + // instantiated, which is useful to catch unintended conversions + typename T::STRING_TO_TEMPLATE_NOT_DEFINED_FOR_THIS_TYPE invalid_type; + return T(); +} + +template <> +inline bool string_to (const std::string& str) +{ + bool tmp; + string_to_bool (str, tmp); + return tmp; +} + +template <> +inline int8_t string_to (const std::string& str) +{ + int16_t tmp; + string_to_int16 (str, tmp); + return tmp; +} + +template <> +inline uint8_t string_to (const std::string& str) +{ + uint16_t tmp; + string_to_uint16 (str, tmp); + return tmp; +} + +template <> +inline int16_t string_to (const std::string& str) +{ + int16_t tmp; + string_to_int16 (str, tmp); + return tmp; +} + +template <> +inline uint16_t string_to (const std::string& str) +{ + uint16_t tmp; + string_to_uint16 (str, tmp); + return tmp; +} + +template <> +inline int32_t string_to (const std::string& str) +{ + int32_t tmp; + string_to_int32 (str, tmp); + return tmp; +} + +template <> +inline uint32_t string_to (const std::string& str) +{ + uint32_t tmp; + string_to_uint32 (str, tmp); + return tmp; +} + +template <> +inline int64_t string_to (const std::string& str) +{ + int64_t tmp; + string_to_int64 (str, tmp); + return tmp; +} + +template <> +inline uint64_t string_to (const std::string& str) +{ + uint64_t tmp; + string_to_uint64 (str, tmp); + return tmp; +} + +template <> +inline float string_to (const std::string& str) +{ + float tmp; + string_to_float (str, tmp); + return tmp; +} + +template <> +inline double string_to (const std::string& str) +{ + double tmp; + string_to_double (str, tmp); + return tmp; +} + +} // namespace PBD + +#endif // PBD_STRING_CONVERT_H -- cgit v1.2.3