1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
#pragma once
#include "math/Vector3.h"
#include "math/Vector4.h"
#include <sstream>
#include <cstdlib>
namespace string
{
/**
* @brief Convert a string to a different type, returning a default value if the conversion
* did not succeed.
*
* @tparam T
* Type of destination value. May be any type for which stringstream::operator>>() is
* defined.
*/
template<typename T> T convert(const std::string& str, T defaultVal = {}) noexcept
{
std::stringstream stream(str);
T result;
stream >> result;
if (stream.fail())
return defaultVal;
else
return result;
}
// Template specialisation to convert std::string => bool
// Returns the default value if the string is empty, everything else except "0" returns true
template<> inline bool convert<bool>(const std::string& str, bool defaultVal) noexcept
{
return str.empty() ? defaultVal : (str != "0");
}
/**
* @brief Identity "conversion" from std::string to std::string.
*
* Not much point in calling this explicitly, but might improve performance if found by
* type-based lookup in a templated function that calls convert<T>(), since it does not
* construct a stringstream.
*/
template<> inline std::string convert<std::string>(const std::string& str,
std::string defaultVal) noexcept
{
return str;
}
#ifdef SPECIALISE_STR_TO_FLOAT
/**
* \brief
* Convert a string to a float.
*
* If the SPECIALISE_STR_TO_FLOAT macro is defined, this will use the atof() C
* function instead of convert<float>() which may provide a speed benefit.
*
* \internal
* This is a separate function rather than an actual specialisation of
* convert<>() for two reasons: (1) I could not get the specialisation to work
* (i.e. be chosen by the compiler), and (2) since when using atof() there is no
* reliable way to use the fallback value, the default value argument would be
* ignored and hence the user-visible function behaviour would change in the
* specialised version, which is a bad thing.
*/
template<typename Src> double to_float(const Src& str)
{
return std::atof(str.c_str());
}
#else
template<typename Src> float to_float(const Src& src)
{
return convert<float>(src, 0.0f);
}
#endif
// Attempts to convert the given source string to a float value,
// returning true on success. The value reference will then be holding
// the resulting float value (or 0 in case of failure).
// Note: this is using the exception-less std::strtof, making it preferable
// over the string::convert<float> method (in certain hot code paths).
inline bool tryConvertToFloat(const std::string& src, float& value)
{
char* lastChar;
auto* firstChar = src.c_str();
value = std::strtof(firstChar, &lastChar);
return lastChar != firstChar;
}
// Attempts to convert the given source string to an int value,
// returning true on success. The value reference will then be holding
// the resulting int value (or 0 in case of failure).
// Note: this is using the exception-less std::strtol, making it preferable
// over the string::convert<int> method (in certain hot code paths).
inline bool tryConvertToInt(const std::string& src, int& value)
{
char* lastChar;
auto* firstChar = src.c_str();
value = static_cast<int>(std::strtol(firstChar, &lastChar, 10));
return lastChar != firstChar;
}
// Convert the given type to a std::string
template<typename Src>
inline std::string to_string(const Src& value)
{
return std::to_string(value);
}
// Specialisation for Vector3
template<>
inline std::string to_string<Vector3>(const Vector3& value)
{
std::stringstream str;
str << value;
return str.str();
}
// Specialisation for std::string
template<>
inline std::string to_string<std::string>(const std::string& value)
{
return value;
}
// Special overload for converting const char* to string (this might actually
// happen in other template<T> functions calling to_string<T> with T = const char*
inline std::string to_string(const char* value)
{
return value;
}
}
|