* Use enum class instead of enum (except for the enums for the resource IDs, not really necessary there).
* For NCSF specifically, included a function to convert an enum class to its underlying integral type (as this is needed for use with the std::bitset class).
* Cleanup headers so all the ones needed in a file are explicitly included even if they may possibly be included in another header.
* Used forward declarations in a few spots.
* Explicitly namespaced all (u)int*_t uses (this might seem like overkill, but it helps me see when the standard types are being used with a simple search for std::).
* Made sure it all builds with MinGW-w64 as well (both gcc and clang).
* Removed some std::move from DialogBuilder.cpp based on clang's warnings for that.
* Replaced use of std::copy_n on strings in DialogBuilder.cpp with my CopyToString functions that use wcscpy.
* Replaced CHAR_MIN/CHAR_MAX in eqstr.h and ltstr.h with std::numeric_limits<char>::min/max().
| ... | ... |
@@ -5,13 +5,12 @@ |
| 5 | 5 |
|
| 6 | 6 |
#pragma once |
| 7 | 7 |
|
| 8 |
-#include <string> |
|
| 9 |
-#include <sstream> |
|
| 10 | 8 |
#include <locale> |
| 11 |
-#include <vector> |
|
| 12 |
-#include <memory> |
|
| 9 |
+#include <string> |
|
| 13 | 10 |
#include <type_traits> |
| 11 |
+#include <vector> |
|
| 14 | 12 |
#include <cmath> |
| 13 |
+#include <cstddef> |
|
| 15 | 14 |
#include "windowsh_wrapper.h" |
| 16 | 15 |
|
| 17 | 16 |
/* |
| ... | ... |
@@ -62,10 +61,10 @@ private: |
| 62 | 61 |
template<typename T> static bool IsDigitsOnly(const std::basic_string<T> &input, const std::locale &loc = std::locale::classic()) |
| 63 | 62 |
{
|
| 64 | 63 |
auto inputChars = std::vector<T>(input.begin(), input.end()); |
| 65 |
- size_t length = inputChars.size(); |
|
| 64 |
+ std::size_t length = inputChars.size(); |
|
| 66 | 65 |
auto masks = std::vector<typename std::ctype<T>::mask>(length); |
| 67 | 66 |
std::use_facet<std::ctype<T>>(loc).is(&inputChars[0], &inputChars[length], &masks[0]); |
| 68 |
- for (size_t x = 0; x < length; ++x) |
|
| 67 |
+ for (std::size_t x = 0; x < length; ++x) |
|
| 69 | 68 |
if (inputChars[x] != '.' && !(masks[x] & std::ctype<T>::digit)) |
| 70 | 69 |
return false; |
| 71 | 70 |
return true; |
| ... | ... |
@@ -77,10 +76,10 @@ public: |
| 77 | 76 |
unsigned long hours = 0, minutes = 0; |
| 78 | 77 |
double seconds = 0.0; |
| 79 | 78 |
std::string hoursStr, minutesStr, secondsStr; |
| 80 |
- size_t firstcolon = time.find(':');
|
|
| 79 |
+ std::size_t firstcolon = time.find(':');
|
|
| 81 | 80 |
if (firstcolon != std::string::npos) |
| 82 | 81 |
{
|
| 83 |
- size_t secondcolon = time.substr(firstcolon + 1).find(':');
|
|
| 82 |
+ std::size_t secondcolon = time.substr(firstcolon + 1).find(':');
|
|
| 84 | 83 |
if (secondcolon != std::string::npos) |
| 85 | 84 |
{
|
| 86 | 85 |
secondcolon = firstcolon + secondcolon + 1; |
| ... | ... |
@@ -112,7 +111,7 @@ public: |
| 112 | 111 |
{
|
| 113 | 112 |
if (!ConvertFuncs::IsDigitsOnly(secondsStr)) |
| 114 | 113 |
return 0; |
| 115 |
- size_t comma = secondsStr.find(',');
|
|
| 114 |
+ std::size_t comma = secondsStr.find(',');
|
|
| 116 | 115 |
if (comma != std::string::npos) |
| 117 | 116 |
secondsStr[comma] = '.'; |
| 118 | 117 |
seconds = convertTo<double>(secondsStr); |
| ... | ... |
@@ -14,14 +14,14 @@ |
| 14 | 14 |
#include <cmath> |
| 15 | 15 |
#include "windowsh_wrapper.h" |
| 16 | 16 |
|
| 17 |
- /* |
|
| 18 |
- * Originally the convert* functions came from the C++ FAQ, Miscellaneous Technical Issues: |
|
| 19 |
- * https://isocpp.org/wiki/faq/misc-technical-issues#convert-string-to-any |
|
| 20 |
- * |
|
| 21 |
- * They have been replaced with a couple functions that use the C++11 std::enable_if |
|
| 22 |
- * construct along with various other type traits constructs to use the proper |
|
| 23 |
- * string conversions. |
|
| 24 |
- */ |
|
| 17 |
+/* |
|
| 18 |
+ * Originally the convert* functions came from the C++ FAQ, Miscellaneous Technical Issues: |
|
| 19 |
+ * https://isocpp.org/wiki/faq/misc-technical-issues#convert-string-to-any |
|
| 20 |
+ * |
|
| 21 |
+ * They have been replaced with a couple functions that use the C++11 std::enable_if |
|
| 22 |
+ * construct along with various other type traits constructs to use the proper |
|
| 23 |
+ * string conversions. |
|
| 24 |
+ */ |
|
| 25 | 25 |
template<typename T, typename S> inline typename std::enable_if_t<!std::is_enum_v<T> &&std::is_arithmetic_v<T>, T> convertTo(const std::basic_string<S> &s) |
| 26 | 26 |
{
|
| 27 | 27 |
if (std::is_integral_v<T>) |
* To go along with the previous change, XSFConfig now had internal get/set value functions that use type traits to choose between the enum and non-enum versions. (This also means I do not need to manually double-cast enums now.)
* Fix bug with the Windows API string conversions, so they do not include the trailing null byte in the output string.
* Added function to trim trailing 0s (and the decimal point if necessary) from a string that came from a double.
| ... | ... |
@@ -130,14 +130,14 @@ public: |
| 130 | 130 |
{
|
| 131 | 131 |
double seconds = time / 1000.0; |
| 132 | 132 |
if (seconds < 60) |
| 133 |
- return std::to_string(seconds); |
|
| 133 |
+ return ConvertFuncs::TrimDoubleString(std::to_string(seconds)); |
|
| 134 | 134 |
unsigned long minutes = static_cast<unsigned long>(seconds) / 60; |
| 135 | 135 |
seconds -= minutes * 60; |
| 136 | 136 |
if (minutes < 60) |
| 137 |
- return std::to_string(minutes) + ":" + (seconds < 10 ? "0" : "") + std::to_string(seconds); |
|
| 137 |
+ return std::to_string(minutes) + ":" + (seconds < 10 ? "0" : "") + ConvertFuncs::TrimDoubleString(std::to_string(seconds)); |
|
| 138 | 138 |
unsigned long hours = minutes / 60; |
| 139 | 139 |
minutes %= 60; |
| 140 |
- return std::to_string(hours) + ":" + (minutes < 10 ? "0" : "") + std::to_string(minutes) + ":" + (seconds < 10 ? "0" : "") + std::to_string(seconds); |
|
| 140 |
+ return std::to_string(hours) + ":" + (minutes < 10 ? "0" : "") + std::to_string(minutes) + ":" + (seconds < 10 ? "0" : "") + ConvertFuncs::TrimDoubleString(std::to_string(seconds)); |
|
| 141 | 141 |
} |
| 142 | 142 |
|
| 143 | 143 |
static std::wstring MSToWString(unsigned long time) |
| ... | ... |
@@ -145,13 +145,22 @@ public: |
| 145 | 145 |
return ConvertFuncs::StringToWString(ConvertFuncs::MSToString(time)); |
| 146 | 146 |
} |
| 147 | 147 |
|
| 148 |
+ // Derived from https://stackoverflow.com/a/13709929 (specifically the comments) |
|
| 149 |
+ template<typename T> static std::basic_string<T> TrimDoubleString(const std::basic_string<T> &str) |
|
| 150 |
+ {
|
|
| 151 |
+ auto strCopy = str; |
|
| 152 |
+ auto lastNonZero = strCopy.find_last_not_of('0');
|
|
| 153 |
+ strCopy.erase(lastNonZero + (lastNonZero == strCopy.find('.') ? 0 : 1));
|
|
| 154 |
+ return strCopy; |
|
| 155 |
+ } |
|
| 156 |
+ |
|
| 148 | 157 |
static std::wstring StringToWString(const std::string &str) |
| 149 | 158 |
{
|
| 150 | 159 |
auto strC = str.c_str(); |
| 151 | 160 |
int bufferSize = MultiByteToWideChar(CP_UTF8, 0, strC, -1, nullptr, 0); |
| 152 | 161 |
auto buffer = std::vector<wchar_t>(bufferSize); |
| 153 | 162 |
MultiByteToWideChar(CP_UTF8, 0, strC, -1, &buffer[0], bufferSize); |
| 154 |
- return std::wstring(buffer.begin(), buffer.end()); |
|
| 163 |
+ return std::wstring(buffer.begin(), buffer.begin() + bufferSize - 1); |
|
| 155 | 164 |
} |
| 156 | 165 |
|
| 157 | 166 |
static std::string WStringToString(const std::wstring &wstr) |
| ... | ... |
@@ -160,6 +169,6 @@ public: |
| 160 | 169 |
int bufferSize = WideCharToMultiByte(CP_UTF8, 0, wstrC, -1, nullptr, 0, nullptr, nullptr); |
| 161 | 170 |
auto buffer = std::vector<char>(bufferSize); |
| 162 | 171 |
WideCharToMultiByte(CP_UTF8, 0, wstrC, -1, &buffer[0], bufferSize, nullptr, nullptr); |
| 163 |
- return std::string(buffer.begin(), buffer.end()); |
|
| 172 |
+ return std::string(buffer.begin(), buffer.begin() + bufferSize - 1); |
|
| 164 | 173 |
} |
| 165 | 174 |
}; |
* Replace the (w)stringify functions with the standard std::to_(w)string functions.
* Replace convertTo with versions that use type_traits to determine which standard string conversion function to call, as well as handle enums specically.
| ... | ... |
@@ -5,61 +5,54 @@ |
| 5 | 5 |
|
| 6 | 6 |
#pragma once |
| 7 | 7 |
|
| 8 |
-#include <stdexcept> |
|
| 9 | 8 |
#include <string> |
| 10 | 9 |
#include <sstream> |
| 11 |
-#include <typeinfo> |
|
| 12 | 10 |
#include <locale> |
| 13 |
-#include <codecvt> |
|
| 14 | 11 |
#include <vector> |
| 15 | 12 |
#include <memory> |
| 13 |
+#include <type_traits> |
|
| 16 | 14 |
#include <cmath> |
| 17 | 15 |
#include "windowsh_wrapper.h" |
| 18 | 16 |
|
| 19 |
-/* |
|
| 20 |
- * The following exception class and the *stringify and convert* functions are |
|
| 21 |
- * from the C++ FAQ, section 39, entry 3: |
|
| 22 |
- * http://www.parashift.com/c++-faq/convert-string-to-any.html |
|
| 23 |
- * |
|
| 24 |
- * The convert and convertTo functions were made into templates of std::basic_string |
|
| 25 |
- * to handle wide-character strings properly, as well as adding wstringify for the |
|
| 26 |
- * same reason. |
|
| 27 |
- */ |
|
| 28 |
-class BadConversion : public std::runtime_error |
|
| 29 |
-{
|
|
| 30 |
-public: |
|
| 31 |
- BadConversion(const std::string &s) : std::runtime_error(s) { }
|
|
| 32 |
-}; |
|
| 33 |
- |
|
| 34 |
-template<typename T> inline std::string stringify(const T &x) |
|
| 35 |
-{
|
|
| 36 |
- std::ostringstream o; |
|
| 37 |
- if (!(o << x)) |
|
| 38 |
- throw BadConversion(std::string("stringify(") + typeid(x).name() + ")");
|
|
| 39 |
- return o.str(); |
|
| 40 |
-} |
|
| 41 |
- |
|
| 42 |
-template<typename T> inline std::wstring wstringify(const T &x) |
|
| 43 |
-{
|
|
| 44 |
- std::wostringstream o; |
|
| 45 |
- if (!(o << x)) |
|
| 46 |
- throw BadConversion(std::string("wstringify(") + typeid(x).name() + ")");
|
|
| 47 |
- return o.str(); |
|
| 48 |
-} |
|
| 49 |
- |
|
| 50 |
-template<typename T, typename S> inline void convert(const std::basic_string<S> &s, T &x, bool failIfLeftoverChars = true) |
|
| 17 |
+ /* |
|
| 18 |
+ * Originally the convert* functions came from the C++ FAQ, Miscellaneous Technical Issues: |
|
| 19 |
+ * https://isocpp.org/wiki/faq/misc-technical-issues#convert-string-to-any |
|
| 20 |
+ * |
|
| 21 |
+ * They have been replaced with a couple functions that use the C++11 std::enable_if |
|
| 22 |
+ * construct along with various other type traits constructs to use the proper |
|
| 23 |
+ * string conversions. |
|
| 24 |
+ */ |
|
| 25 |
+template<typename T, typename S> inline typename std::enable_if_t<!std::is_enum_v<T> &&std::is_arithmetic_v<T>, T> convertTo(const std::basic_string<S> &s) |
|
| 51 | 26 |
{
|
| 52 |
- std::basic_istringstream<S> i(s); |
|
| 53 |
- S c; |
|
| 54 |
- if (!(i >> x) || (failIfLeftoverChars && i.get(c))) |
|
| 55 |
- throw BadConversion(std::string("convert(") + typeid(S).name() + ")");
|
|
| 27 |
+ if (std::is_integral_v<T>) |
|
| 28 |
+ {
|
|
| 29 |
+ if (std::is_unsigned_v<T>) |
|
| 30 |
+ {
|
|
| 31 |
+ if (std::is_same_v<unsigned long long, std::remove_cv_t<T>>) |
|
| 32 |
+ return static_cast<T>(std::stoull(s)); |
|
| 33 |
+ else |
|
| 34 |
+ return static_cast<T>(std::stoul(s)); |
|
| 35 |
+ } |
|
| 36 |
+ else if (std::is_same_v<long long, std::remove_cv_t<T>>) |
|
| 37 |
+ return static_cast<T>(std::stoll(s)); |
|
| 38 |
+ else if (std::is_same_v<long, std::remove_cv_t<T>>) |
|
| 39 |
+ return static_cast<T>(std::stol(s)); |
|
| 40 |
+ else |
|
| 41 |
+ return static_cast<T>(std::stoi(s)); |
|
| 42 |
+ } |
|
| 43 |
+ else if (std::is_floating_point_v<T>) |
|
| 44 |
+ {
|
|
| 45 |
+ if (std::is_same_v<long double, std::remove_cv_t<T>>) |
|
| 46 |
+ return static_cast<T>(std::stold(s)); |
|
| 47 |
+ else if (std::is_same_v<double, std::remove_cv_t<T>>) |
|
| 48 |
+ return static_cast<T>(std::stod(s)); |
|
| 49 |
+ else |
|
| 50 |
+ return static_cast<T>(std::stof(s)); |
|
| 51 |
+ } |
|
| 56 | 52 |
} |
| 57 |
- |
|
| 58 |
-template<typename T, typename S> inline T convertTo(const std::basic_string<S> &s, bool failIfLeftoverChars = true) |
|
| 53 |
+template<typename T, typename S> inline typename std::enable_if_t<std::is_enum_v<T>, T> convertTo(const std::basic_string<S> &s) |
|
| 59 | 54 |
{
|
| 60 |
- T x; |
|
| 61 |
- convert(s, x, failIfLeftoverChars); |
|
| 62 |
- return x; |
|
| 55 |
+ return static_cast<T>(convertTo<std::underlying_type_t<T>>(s)); |
|
| 63 | 56 |
} |
| 64 | 57 |
|
| 65 | 58 |
// Miscellaneous conversion functions |
| ... | ... |
@@ -107,13 +100,13 @@ public: |
| 107 | 100 |
{
|
| 108 | 101 |
if (!ConvertFuncs::IsDigitsOnly(hoursStr)) |
| 109 | 102 |
return 0; |
| 110 |
- hours = convertTo<unsigned long>(hoursStr, false); |
|
| 103 |
+ hours = convertTo<unsigned long>(hoursStr); |
|
| 111 | 104 |
} |
| 112 | 105 |
if (!minutesStr.empty()) |
| 113 | 106 |
{
|
| 114 | 107 |
if (!ConvertFuncs::IsDigitsOnly(minutesStr)) |
| 115 | 108 |
return 0; |
| 116 |
- minutes = convertTo<unsigned long>(minutesStr, false); |
|
| 109 |
+ minutes = convertTo<unsigned long>(minutesStr); |
|
| 117 | 110 |
} |
| 118 | 111 |
if (!secondsStr.empty()) |
| 119 | 112 |
{
|
| ... | ... |
@@ -122,7 +115,7 @@ public: |
| 122 | 115 |
size_t comma = secondsStr.find(',');
|
| 123 | 116 |
if (comma != std::string::npos) |
| 124 | 117 |
secondsStr[comma] = '.'; |
| 125 |
- seconds = convertTo<double>(secondsStr, false); |
|
| 118 |
+ seconds = convertTo<double>(secondsStr); |
|
| 126 | 119 |
} |
| 127 | 120 |
seconds += minutes * 60 + hours * 1440; |
| 128 | 121 |
return static_cast<unsigned long>(std::floor(seconds * 1000 + 0.5)); |
| ... | ... |
@@ -137,14 +130,14 @@ public: |
| 137 | 130 |
{
|
| 138 | 131 |
double seconds = time / 1000.0; |
| 139 | 132 |
if (seconds < 60) |
| 140 |
- return stringify(seconds); |
|
| 133 |
+ return std::to_string(seconds); |
|
| 141 | 134 |
unsigned long minutes = static_cast<unsigned long>(seconds) / 60; |
| 142 | 135 |
seconds -= minutes * 60; |
| 143 | 136 |
if (minutes < 60) |
| 144 |
- return stringify(minutes) + ":" + (seconds < 10 ? "0" : "") + stringify(seconds); |
|
| 137 |
+ return std::to_string(minutes) + ":" + (seconds < 10 ? "0" : "") + std::to_string(seconds); |
|
| 145 | 138 |
unsigned long hours = minutes / 60; |
| 146 | 139 |
minutes %= 60; |
| 147 |
- return stringify(hours) + ":" + (minutes < 10 ? "0" : "") + stringify(minutes) + ":" + (seconds < 10 ? "0" : "") + stringify(seconds); |
|
| 140 |
+ return std::to_string(hours) + ":" + (minutes < 10 ? "0" : "") + std::to_string(minutes) + ":" + (seconds < 10 ? "0" : "") + std::to_string(seconds); |
|
| 148 | 141 |
} |
| 149 | 142 |
|
| 150 | 143 |
static std::wstring MSToWString(unsigned long time) |
| ... | ... |
@@ -14,6 +14,7 @@ |
| 14 | 14 |
#include <vector> |
| 15 | 15 |
#include <memory> |
| 16 | 16 |
#include <cmath> |
| 17 |
+#include "windowsh_wrapper.h" |
|
| 17 | 18 |
|
| 18 | 19 |
/* |
| 19 | 20 |
* The following exception class and the *stringify and convert* functions are |
| ... | ... |
@@ -153,13 +154,19 @@ public: |
| 153 | 154 |
|
| 154 | 155 |
static std::wstring StringToWString(const std::string &str) |
| 155 | 156 |
{
|
| 156 |
- static std::wstring_convert<std::codecvt_utf8<wchar_t>> conv; |
|
| 157 |
- return conv.from_bytes(str); |
|
| 157 |
+ auto strC = str.c_str(); |
|
| 158 |
+ int bufferSize = MultiByteToWideChar(CP_UTF8, 0, strC, -1, nullptr, 0); |
|
| 159 |
+ auto buffer = std::vector<wchar_t>(bufferSize); |
|
| 160 |
+ MultiByteToWideChar(CP_UTF8, 0, strC, -1, &buffer[0], bufferSize); |
|
| 161 |
+ return std::wstring(buffer.begin(), buffer.end()); |
|
| 158 | 162 |
} |
| 159 | 163 |
|
| 160 | 164 |
static std::string WStringToString(const std::wstring &wstr) |
| 161 | 165 |
{
|
| 162 |
- static std::wstring_convert<std::codecvt_utf8<wchar_t>> conv; |
|
| 163 |
- return conv.to_bytes(wstr); |
|
| 166 |
+ auto wstrC = wstr.c_str(); |
|
| 167 |
+ int bufferSize = WideCharToMultiByte(CP_UTF8, 0, wstrC, -1, nullptr, 0, nullptr, nullptr); |
|
| 168 |
+ auto buffer = std::vector<char>(bufferSize); |
|
| 169 |
+ WideCharToMultiByte(CP_UTF8, 0, wstrC, -1, &buffer[0], bufferSize, nullptr, nullptr); |
|
| 170 |
+ return std::string(buffer.begin(), buffer.end()); |
|
| 164 | 171 |
} |
| 165 | 172 |
}; |
(I never remember to update these and besides, GitHub history can show when they were last modified.)
| ... | ... |
@@ -11,12 +11,7 @@ |
| 11 | 11 |
#include <sstream> |
| 12 | 12 |
#include <typeinfo> |
| 13 | 13 |
#include <locale> |
| 14 |
-#if (defined(__GNUC__) || defined(__clang__)) && !defined(_LIBCPP_VERSION) |
|
| 15 |
-# include "wstring_convert.h" |
|
| 16 |
-# include "codecvt.h" |
|
| 17 |
-#else |
|
| 18 |
-# include <codecvt> |
|
| 19 |
-#endif |
|
| 14 |
+#include <codecvt> |
|
| 20 | 15 |
#include <vector> |
| 21 | 16 |
#include <memory> |
| 22 | 17 |
#include <cmath> |
* Removed my custom String class, as well as removed the really old
Unicode ConvertUTF, the UTF Converter, and the UTF Encode/Decode
functions.
* Replaced the above with using standard C++ std::wstring_convert and
std::codecvt_utf8.
* Added headers adapted from llvm's libc++ project for allowing the
above C++ classes to exist with GCC and Clang when libc++ isn't being
used.
* Used std::string over std::wstring whenever possible.
* Added header adapted from llvm's libc++ project to create special
versions of the ifstream and ofstream classes that would utilize _wfopen
on non-MSVC Windows compilers, so those compilers could access files on
Windows that use characters outside the current codepage.
* Removed the -static-libgcc and -static-libstdc++ flags from the
Makefile for non-MSVC builds. The generated DLLs will require extra DLLs
from either Cygwin or MinGW (whichever is used to compile), I've only
tested with MinGW and for some reason they crash Winamp on exit, I have
no idea why.
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* Common conversion functions |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2014-09-17 |
|
| 4 |
+ * Last modification on 2014-09-24 |
|
| 5 | 5 |
*/ |
| 6 | 6 |
|
| 7 | 7 |
#pragma once |
| ... | ... |
@@ -11,10 +11,15 @@ |
| 11 | 11 |
#include <sstream> |
| 12 | 12 |
#include <typeinfo> |
| 13 | 13 |
#include <locale> |
| 14 |
+#if (defined(__GNUC__) || defined(__clang__)) && !defined(_LIBCPP_VERSION) |
|
| 15 |
+# include "wstring_convert.h" |
|
| 16 |
+# include "codecvt.h" |
|
| 17 |
+#else |
|
| 18 |
+# include <codecvt> |
|
| 19 |
+#endif |
|
| 14 | 20 |
#include <vector> |
| 15 | 21 |
#include <memory> |
| 16 | 22 |
#include <cmath> |
| 17 |
-#include "BigSString.h" |
|
| 18 | 23 |
|
| 19 | 24 |
/* |
| 20 | 25 |
* The following exception class and the *stringify and convert* functions are |
| ... | ... |
@@ -130,7 +135,7 @@ public: |
| 130 | 135 |
|
| 131 | 136 |
static unsigned long StringToMS(const std::wstring &time) |
| 132 | 137 |
{
|
| 133 |
- return ConvertFuncs::StringToMS(String(time).GetAnsi()); |
|
| 138 |
+ return ConvertFuncs::StringToMS(ConvertFuncs::WStringToString(time)); |
|
| 134 | 139 |
} |
| 135 | 140 |
|
| 136 | 141 |
static std::string MSToString(unsigned long time) |
| ... | ... |
@@ -149,6 +154,18 @@ public: |
| 149 | 154 |
|
| 150 | 155 |
static std::wstring MSToWString(unsigned long time) |
| 151 | 156 |
{
|
| 152 |
- return String(ConvertFuncs::MSToString(time)).GetWStr(); |
|
| 157 |
+ return ConvertFuncs::StringToWString(ConvertFuncs::MSToString(time)); |
|
| 158 |
+ } |
|
| 159 |
+ |
|
| 160 |
+ static std::wstring StringToWString(const std::string &str) |
|
| 161 |
+ {
|
|
| 162 |
+ static std::wstring_convert<std::codecvt_utf8<wchar_t>> conv; |
|
| 163 |
+ return conv.from_bytes(str); |
|
| 164 |
+ } |
|
| 165 |
+ |
|
| 166 |
+ static std::string WStringToString(const std::wstring &wstr) |
|
| 167 |
+ {
|
|
| 168 |
+ static std::wstring_convert<std::codecvt_utf8<wchar_t>> conv; |
|
| 169 |
+ return conv.to_bytes(wstr); |
|
| 153 | 170 |
} |
| 154 | 171 |
}; |
* [2SF] Used more up-to-date asmjit, despite the ugly looking code.
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* Common conversion functions |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2014-09-08 |
|
| 4 |
+ * Last modification on 2014-09-17 |
|
| 5 | 5 |
*/ |
| 6 | 6 |
|
| 7 | 7 |
#pragma once |
| ... | ... |
@@ -12,6 +12,7 @@ |
| 12 | 12 |
#include <typeinfo> |
| 13 | 13 |
#include <locale> |
| 14 | 14 |
#include <vector> |
| 15 |
+#include <memory> |
|
| 15 | 16 |
#include <cmath> |
| 16 | 17 |
#include "BigSString.h" |
| 17 | 18 |
|
| ... | ... |
@@ -48,7 +49,7 @@ template<typename T> inline std::wstring wstringify(const T &x) |
| 48 | 49 |
|
| 49 | 50 |
template<typename T, typename S> inline void convert(const std::basic_string<S> &s, T &x, bool failIfLeftoverChars = true) |
| 50 | 51 |
{
|
| 51 |
- auto i = std::basic_istringstream<S>(s); |
|
| 52 |
+ std::basic_istringstream<S> i(s); |
|
| 52 | 53 |
S c; |
| 53 | 54 |
if (!(i >> x) || (failIfLeftoverChars && i.get(c))) |
| 54 | 55 |
throw BadConversion(std::string("convert(") + typeid(S).name() + ")");
|
| ... | ... |
@@ -69,7 +70,7 @@ private: |
| 69 | 70 |
{
|
| 70 | 71 |
auto inputChars = std::vector<T>(input.begin(), input.end()); |
| 71 | 72 |
size_t length = inputChars.size(); |
| 72 |
- auto masks = std::vector<std::ctype<T>::mask>(length); |
|
| 73 |
+ auto masks = std::vector<typename std::ctype<T>::mask>(length); |
|
| 73 | 74 |
std::use_facet<std::ctype<T>>(loc).is(&inputChars[0], &inputChars[length], &masks[0]); |
| 74 | 75 |
for (size_t x = 0; x < length; ++x) |
| 75 | 76 |
if (inputChars[x] != '.' && !(masks[x] & std::ctype<T>::digit)) |
| ... | ... |
@@ -1,11 +1,10 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* Common conversion functions |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-04-23 |
|
| 4 |
+ * Last modification on 2014-09-08 |
|
| 5 | 5 |
*/ |
| 6 | 6 |
|
| 7 |
-#ifndef _CONVERT_H_ |
|
| 8 |
-#define _CONVERT_H_ |
|
| 7 |
+#pragma once |
|
| 9 | 8 |
|
| 10 | 9 |
#include <stdexcept> |
| 11 | 10 |
#include <string> |
| ... | ... |
@@ -152,5 +151,3 @@ public: |
| 152 | 151 |
return String(ConvertFuncs::MSToString(time)).GetWStr(); |
| 153 | 152 |
} |
| 154 | 153 |
}; |
| 155 |
- |
|
| 156 |
-#endif |
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* Common conversion functions |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-03-30 |
|
| 4 |
+ * Last modification on 2013-04-23 |
|
| 5 | 5 |
*/ |
| 6 | 6 |
|
| 7 | 7 |
#ifndef _CONVERT_H_ |
| ... | ... |
@@ -66,14 +66,14 @@ template<typename T, typename S> inline T convertTo(const std::basic_string<S> & |
| 66 | 66 |
class ConvertFuncs |
| 67 | 67 |
{
|
| 68 | 68 |
private: |
| 69 |
- static inline bool IsDigitsOnly(const std::string &input, const std::locale &loc = std::locale::classic()) |
|
| 69 |
+ template<typename T> static bool IsDigitsOnly(const std::basic_string<T> &input, const std::locale &loc = std::locale::classic()) |
|
| 70 | 70 |
{
|
| 71 |
- auto inputChars = std::vector<char>(input.begin(), input.end()); |
|
| 71 |
+ auto inputChars = std::vector<T>(input.begin(), input.end()); |
|
| 72 | 72 |
size_t length = inputChars.size(); |
| 73 |
- auto masks = std::vector<std::ctype<char>::mask>(length); |
|
| 74 |
- std::use_facet<std::ctype<char>>(loc).is(&inputChars[0], &inputChars[length], &masks[0]); |
|
| 73 |
+ auto masks = std::vector<std::ctype<T>::mask>(length); |
|
| 74 |
+ std::use_facet<std::ctype<T>>(loc).is(&inputChars[0], &inputChars[length], &masks[0]); |
|
| 75 | 75 |
for (size_t x = 0; x < length; ++x) |
| 76 |
- if (inputChars[x] != '.' && !(masks[x] & std::ctype<char>::digit)) |
|
| 76 |
+ if (inputChars[x] != '.' && !(masks[x] & std::ctype<T>::digit)) |
|
| 77 | 77 |
return false; |
| 78 | 78 |
return true; |
| 79 | 79 |
} |
| ... | ... |
@@ -71,7 +71,7 @@ private: |
| 71 | 71 |
auto inputChars = std::vector<char>(input.begin(), input.end()); |
| 72 | 72 |
size_t length = inputChars.size(); |
| 73 | 73 |
auto masks = std::vector<std::ctype<char>::mask>(length); |
| 74 |
- std::use_facet<std::ctype<char> >(loc).is(&inputChars[0], &inputChars[length], &masks[0]); |
|
| 74 |
+ std::use_facet<std::ctype<char>>(loc).is(&inputChars[0], &inputChars[length], &masks[0]); |
|
| 75 | 75 |
for (size_t x = 0; x < length; ++x) |
| 76 | 76 |
if (inputChars[x] != '.' && !(masks[x] & std::ctype<char>::digit)) |
| 77 | 77 |
return false; |
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* Common conversion functions |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-03-25 |
|
| 4 |
+ * Last modification on 2013-03-28 |
|
| 5 | 5 |
*/ |
| 6 | 6 |
|
| 7 | 7 |
#ifndef _CONVERT_H_ |
| ... | ... |
@@ -66,7 +66,7 @@ template<typename T, typename S> inline T convertTo(const std::basic_string<S> & |
| 66 | 66 |
class ConvertFuncs |
| 67 | 67 |
{
|
| 68 | 68 |
private: |
| 69 |
- static inline bool IsDigitsOnly(const std::string input, const std::locale &loc = std::locale::classic()) |
|
| 69 |
+ static inline bool IsDigitsOnly(const std::string &input, const std::locale &loc = std::locale::classic()) |
|
| 70 | 70 |
{
|
| 71 | 71 |
auto inputChars = std::vector<char>(input.begin(), input.end()); |
| 72 | 72 |
size_t length = inputChars.size(); |
| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,156 @@ |
| 1 |
+/* |
|
| 2 |
+ * Common conversion functions |
|
| 3 |
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
|
| 4 |
+ * Last modification on 2013-03-25 |
|
| 5 |
+ */ |
|
| 6 |
+ |
|
| 7 |
+#ifndef _CONVERT_H_ |
|
| 8 |
+#define _CONVERT_H_ |
|
| 9 |
+ |
|
| 10 |
+#include <stdexcept> |
|
| 11 |
+#include <string> |
|
| 12 |
+#include <sstream> |
|
| 13 |
+#include <typeinfo> |
|
| 14 |
+#include <locale> |
|
| 15 |
+#include <vector> |
|
| 16 |
+#include <cmath> |
|
| 17 |
+#include "BigSString.h" |
|
| 18 |
+ |
|
| 19 |
+/* |
|
| 20 |
+ * The following exception class and the *stringify and convert* functions are |
|
| 21 |
+ * from the C++ FAQ, section 39, entry 3: |
|
| 22 |
+ * http://www.parashift.com/c++-faq/convert-string-to-any.html |
|
| 23 |
+ * |
|
| 24 |
+ * The convert and convertTo functions were made into templates of std::basic_string |
|
| 25 |
+ * to handle wide-character strings properly, as well as adding wstringify for the |
|
| 26 |
+ * same reason. |
|
| 27 |
+ */ |
|
| 28 |
+class BadConversion : public std::runtime_error |
|
| 29 |
+{
|
|
| 30 |
+public: |
|
| 31 |
+ BadConversion(const std::string &s) : std::runtime_error(s) { }
|
|
| 32 |
+}; |
|
| 33 |
+ |
|
| 34 |
+template<typename T> inline std::string stringify(const T &x) |
|
| 35 |
+{
|
|
| 36 |
+ std::ostringstream o; |
|
| 37 |
+ if (!(o << x)) |
|
| 38 |
+ throw BadConversion(std::string("stringify(") + typeid(x).name() + ")");
|
|
| 39 |
+ return o.str(); |
|
| 40 |
+} |
|
| 41 |
+ |
|
| 42 |
+template<typename T> inline std::wstring wstringify(const T &x) |
|
| 43 |
+{
|
|
| 44 |
+ std::wostringstream o; |
|
| 45 |
+ if (!(o << x)) |
|
| 46 |
+ throw BadConversion(std::string("wstringify(") + typeid(x).name() + ")");
|
|
| 47 |
+ return o.str(); |
|
| 48 |
+} |
|
| 49 |
+ |
|
| 50 |
+template<typename T, typename S> inline void convert(const std::basic_string<S> &s, T &x, bool failIfLeftoverChars = true) |
|
| 51 |
+{
|
|
| 52 |
+ auto i = std::basic_istringstream<S>(s); |
|
| 53 |
+ S c; |
|
| 54 |
+ if (!(i >> x) || (failIfLeftoverChars && i.get(c))) |
|
| 55 |
+ throw BadConversion(std::string("convert(") + typeid(S).name() + ")");
|
|
| 56 |
+} |
|
| 57 |
+ |
|
| 58 |
+template<typename T, typename S> inline T convertTo(const std::basic_string<S> &s, bool failIfLeftoverChars = true) |
|
| 59 |
+{
|
|
| 60 |
+ T x; |
|
| 61 |
+ convert(s, x, failIfLeftoverChars); |
|
| 62 |
+ return x; |
|
| 63 |
+} |
|
| 64 |
+ |
|
| 65 |
+// Miscellaneous conversion functions |
|
| 66 |
+class ConvertFuncs |
|
| 67 |
+{
|
|
| 68 |
+private: |
|
| 69 |
+ static inline bool IsDigitsOnly(const std::string input, const std::locale &loc = std::locale::classic()) |
|
| 70 |
+ {
|
|
| 71 |
+ auto inputChars = std::vector<char>(input.begin(), input.end()); |
|
| 72 |
+ size_t length = inputChars.size(); |
|
| 73 |
+ auto masks = std::vector<std::ctype<char>::mask>(length); |
|
| 74 |
+ std::use_facet<std::ctype<char> >(loc).is(&inputChars[0], &inputChars[length], &masks[0]); |
|
| 75 |
+ for (size_t x = 0; x < length; ++x) |
|
| 76 |
+ if (inputChars[x] != '.' && !(masks[x] & std::ctype<char>::digit)) |
|
| 77 |
+ return false; |
|
| 78 |
+ return true; |
|
| 79 |
+ } |
|
| 80 |
+ |
|
| 81 |
+public: |
|
| 82 |
+ static unsigned long StringToMS(const std::string &time) |
|
| 83 |
+ {
|
|
| 84 |
+ unsigned long hours = 0, minutes = 0; |
|
| 85 |
+ double seconds = 0.0; |
|
| 86 |
+ std::string hoursStr, minutesStr, secondsStr; |
|
| 87 |
+ size_t firstcolon = time.find(':');
|
|
| 88 |
+ if (firstcolon != std::string::npos) |
|
| 89 |
+ {
|
|
| 90 |
+ size_t secondcolon = time.substr(firstcolon + 1).find(':');
|
|
| 91 |
+ if (secondcolon != std::string::npos) |
|
| 92 |
+ {
|
|
| 93 |
+ secondcolon = firstcolon + secondcolon + 1; |
|
| 94 |
+ hoursStr = time.substr(0, firstcolon); |
|
| 95 |
+ minutesStr = time.substr(firstcolon + 1, secondcolon - firstcolon - 1); |
|
| 96 |
+ secondsStr = time.substr(secondcolon + 1); |
|
| 97 |
+ } |
|
| 98 |
+ else |
|
| 99 |
+ {
|
|
| 100 |
+ minutesStr = time.substr(0, firstcolon); |
|
| 101 |
+ secondsStr = time.substr(firstcolon + 1); |
|
| 102 |
+ } |
|
| 103 |
+ } |
|
| 104 |
+ else |
|
| 105 |
+ secondsStr = time; |
|
| 106 |
+ if (!hoursStr.empty()) |
|
| 107 |
+ {
|
|
| 108 |
+ if (!ConvertFuncs::IsDigitsOnly(hoursStr)) |
|
| 109 |
+ return 0; |
|
| 110 |
+ hours = convertTo<unsigned long>(hoursStr, false); |
|
| 111 |
+ } |
|
| 112 |
+ if (!minutesStr.empty()) |
|
| 113 |
+ {
|
|
| 114 |
+ if (!ConvertFuncs::IsDigitsOnly(minutesStr)) |
|
| 115 |
+ return 0; |
|
| 116 |
+ minutes = convertTo<unsigned long>(minutesStr, false); |
|
| 117 |
+ } |
|
| 118 |
+ if (!secondsStr.empty()) |
|
| 119 |
+ {
|
|
| 120 |
+ if (!ConvertFuncs::IsDigitsOnly(secondsStr)) |
|
| 121 |
+ return 0; |
|
| 122 |
+ size_t comma = secondsStr.find(',');
|
|
| 123 |
+ if (comma != std::string::npos) |
|
| 124 |
+ secondsStr[comma] = '.'; |
|
| 125 |
+ seconds = convertTo<double>(secondsStr, false); |
|
| 126 |
+ } |
|
| 127 |
+ seconds += minutes * 60 + hours * 1440; |
|
| 128 |
+ return static_cast<unsigned long>(std::floor(seconds * 1000 + 0.5)); |
|
| 129 |
+ } |
|
| 130 |
+ |
|
| 131 |
+ static unsigned long StringToMS(const std::wstring &time) |
|
| 132 |
+ {
|
|
| 133 |
+ return ConvertFuncs::StringToMS(String(time).GetAnsi()); |
|
| 134 |
+ } |
|
| 135 |
+ |
|
| 136 |
+ static std::string MSToString(unsigned long time) |
|
| 137 |
+ {
|
|
| 138 |
+ double seconds = time / 1000.0; |
|
| 139 |
+ if (seconds < 60) |
|
| 140 |
+ return stringify(seconds); |
|
| 141 |
+ unsigned long minutes = static_cast<unsigned long>(seconds) / 60; |
|
| 142 |
+ seconds -= minutes * 60; |
|
| 143 |
+ if (minutes < 60) |
|
| 144 |
+ return stringify(minutes) + ":" + (seconds < 10 ? "0" : "") + stringify(seconds); |
|
| 145 |
+ unsigned long hours = minutes / 60; |
|
| 146 |
+ minutes %= 60; |
|
| 147 |
+ return stringify(hours) + ":" + (minutes < 10 ? "0" : "") + stringify(minutes) + ":" + (seconds < 10 ? "0" : "") + stringify(seconds); |
|
| 148 |
+ } |
|
| 149 |
+ |
|
| 150 |
+ static std::wstring MSToWString(unsigned long time) |
|
| 151 |
+ {
|
|
| 152 |
+ return String(ConvertFuncs::MSToString(time)).GetWStr(); |
|
| 153 |
+ } |
|
| 154 |
+}; |
|
| 155 |
+ |
|
| 156 |
+#endif |