1
0

mptStringFormat.h 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. /*
  2. * mptStringFormat.h
  3. * -----------------
  4. * Purpose: Convert other types to strings.
  5. * Notes : Currently none.
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #pragma once
  10. #include "openmpt/all/BuildSettings.hpp"
  11. #include "mpt/base/pointer.hpp"
  12. #include "mpt/format/message.hpp"
  13. #include "mpt/format/simple_spec.hpp"
  14. #include "mpt/string/types.hpp"
  15. #include <stdexcept>
  16. #include "mptString.h"
  17. #include "openmpt/base/FlagSet.hpp"
  18. OPENMPT_NAMESPACE_BEGIN
  19. // The following section demands a rationale.
  20. // 1. mpt::afmt::val(), mpt::wfmt::val() and mpt::ufmt::val() mimic the semantics of c++11 std::to_string() and std::to_wstring().
  21. // There is an important difference though. The c++11 versions are specified in terms of sprintf formatting which in turn
  22. // depends on the current C locale. This renders these functions unusable in a library context because the current
  23. // C locale is set by the library-using application and could be anything. There is no way a library can get reliable semantics
  24. // out of these functions. It is thus better to just avoid them.
  25. // ToAString() and ToWString() are based on iostream internally, but the the locale of the stream is forced to std::locale::classic(),
  26. // which results in "C" ASCII locale behavior.
  27. // 2. The full suite of printf-like or iostream like number formatting is generally not required. Instead, a sane subset functionality
  28. // is provided here.
  29. // When formatting integers, it is recommended to use mpt::afmt::dec or mpt::afmt::hex. Appending a template argument '<n>' sets the width,
  30. // the same way as '%nd' would do. Appending a '0' to the function name causes zero-filling as print-like '%0nd' would do. Spelling 'HEX'
  31. // in upper-case generates upper-case hex digits. If these are not known at compile-time, a more verbose FormatValA(int, format) can be
  32. // used.
  33. // 3. mpt::format(format)(...) provides simplified and type-safe message and localization string formatting.
  34. // The only specifier allowed is '{}' enclosing a number n. It references to n-th parameter after the format string (1-based).
  35. // This mimics the behaviour of QString::arg() in QT4/5 or MFC AfxFormatString2(). C printf-like functions offer similar functionality
  36. // with a '%n$TYPE' syntax. In .NET, the syntax is '{n}'. This is useful to support localization strings that can change the parameter
  37. // ordering.
  38. // 4. Every function is available for std::string, std::wstring and mpt::ustring. std::string makes no assumption about the encoding, which
  39. // basically means, it should work for any 7-bit or 8-bit encoding, including for example ASCII, UTF8 or the current locale encoding.
  40. // std::string std::wstring mpt::ustring mpt::tsrtring CString
  41. // mpt::afmt mpt::wfmt mpt::ufmt mpt::tfmt mpt::cfmt
  42. // MPT_AFORMAT("{}") MPT_WFORMAT("{}") MPT_UFORMAT("{}") MPT_TFORMAT("{}") MPT_CFORMAT("{}")
  43. // 5. All functionality here delegates real work outside of the header file so that <sstream> and <locale> do not need to be included when
  44. // using this functionality.
  45. // Advantages:
  46. // - Avoids binary code bloat when too much of iostream operator << gets inlined at every usage site.
  47. // - Faster compile times because <sstream> and <locale> (2 very complex headers) are not included everywhere.
  48. // Disadvantages:
  49. // - Slightly more c++ code is required for delegating work.
  50. // - As the header does not use iostreams, custom types need to overload mpt::UString instead of iostream operator << to allow for custom type
  51. // formatting.
  52. // - std::string, std::wstring and mpt::ustring are returned from somewhat deep cascades of helper functions. Where possible, code is
  53. // written in such a way that return-value-optimization (RVO) or named-return-value-optimization (NRVO) should be able to eliminate
  54. // almost all these copies. This should not be a problem for any decent modern compiler (and even less so for a c++11 compiler where
  55. // move-semantics will kick in if RVO/NRVO fails).
  56. namespace mpt
  57. {
  58. // ToUString() converts various built-in types to a well-defined, locale-independent string representation.
  59. // This is also used as a type-tunnel pattern for mpt::format.
  60. // Custom types that need to be converted to strings are encouraged to overload ToUString().
  61. // fallback to member function ToUString()
  62. #if MPT_USTRING_MODE_UTF8
  63. template <typename T> [[deprecated]] auto ToAString(const T & x) -> decltype(mpt::ToCharset(mpt::Charset::UTF8, x.ToUString())) { return mpt::ToCharset(mpt::Charset::UTF8, x.ToUString()); } // unknown encoding
  64. #else
  65. #if defined(MPT_ENABLE_CHARSET_LOCALE)
  66. template <typename T> [[deprecated]] auto ToAString(const T & x) -> decltype(mpt::ToCharset(mpt::Charset::Locale, x.ToUString())) { return mpt::ToCharset(mpt::Charset::Locale, x.ToUString()); } // unknown encoding
  67. #else // !MPT_ENABLE_CHARSET_LOCALE
  68. template <typename T> [[deprecated]] auto ToAString(const T & x) -> decltype(mpt::ToCharset(mpt::Charset::UTF8, x.ToUString())) { return mpt::ToCharset(mpt::Charset::UTF8, x.ToUString()); } // unknown encoding
  69. #endif // MPT_ENABLE_CHARSET_LOCALE
  70. #endif
  71. inline std::string ToAString(const std::string & x) { return x; }
  72. inline std::string ToAString(const char * const & x) { return x; }
  73. std::string ToAString(const char &x) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead
  74. #if MPT_WSTRING_FORMAT
  75. std::string ToAString(const std::wstring & x) = delete; // Unknown encoding.
  76. std::string ToAString(const wchar_t * const & x) = delete; // Unknown encoding.
  77. std::string ToAString(const wchar_t &x ) = delete; // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
  78. #endif
  79. #if MPT_USTRING_MODE_UTF8
  80. std::string ToAString(const mpt::ustring & x) = delete; // Unknown encoding.
  81. #endif
  82. #if defined(MPT_WITH_MFC)
  83. std::string ToAString(const CString & x) = delete; // unknown encoding
  84. #endif // MPT_WITH_MFC
  85. std::string ToAString(const bool & x);
  86. std::string ToAString(const signed char & x);
  87. std::string ToAString(const unsigned char & x);
  88. std::string ToAString(const signed short & x);
  89. std::string ToAString(const unsigned short & x);
  90. std::string ToAString(const signed int & x);
  91. std::string ToAString(const unsigned int & x);
  92. std::string ToAString(const signed long & x);
  93. std::string ToAString(const unsigned long & x);
  94. std::string ToAString(const signed long long & x);
  95. std::string ToAString(const unsigned long long & x);
  96. std::string ToAString(const float & x);
  97. std::string ToAString(const double & x);
  98. std::string ToAString(const long double & x);
  99. // fallback to member function ToUString()
  100. template <typename T> auto ToUString(const T & x) -> decltype(x.ToUString()) { return x.ToUString(); }
  101. inline mpt::ustring ToUString(const mpt::ustring & x) { return x; }
  102. mpt::ustring ToUString(const std::string & x) = delete; // Unknown encoding.
  103. mpt::ustring ToUString(const char * const & x) = delete; // Unknown encoding. Note that this also applies to TCHAR in !UNICODE builds as the type is indistinguishable from char. Wrap with CString or FromTcharStr in this case.
  104. mpt::ustring ToUString(const char & x) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead
  105. #if MPT_WSTRING_FORMAT
  106. #if MPT_USTRING_MODE_UTF8
  107. mpt::ustring ToUString(const std::wstring & x);
  108. #endif
  109. mpt::ustring ToUString(const wchar_t * const & x);
  110. mpt::ustring ToUString(const wchar_t & x) = delete; // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
  111. #endif
  112. #if defined(MPT_WITH_MFC)
  113. mpt::ustring ToUString(const CString & x);
  114. #endif // MPT_WITH_MFC
  115. mpt::ustring ToUString(const bool & x);
  116. mpt::ustring ToUString(const signed char & x);
  117. mpt::ustring ToUString(const unsigned char & x);
  118. mpt::ustring ToUString(const signed short & x);
  119. mpt::ustring ToUString(const unsigned short & x);
  120. mpt::ustring ToUString(const signed int & x);
  121. mpt::ustring ToUString(const unsigned int & x);
  122. mpt::ustring ToUString(const signed long & x);
  123. mpt::ustring ToUString(const unsigned long & x);
  124. mpt::ustring ToUString(const signed long long & x);
  125. mpt::ustring ToUString(const unsigned long long & x);
  126. mpt::ustring ToUString(const float & x);
  127. mpt::ustring ToUString(const double & x);
  128. mpt::ustring ToUString(const long double & x);
  129. #if MPT_WSTRING_FORMAT
  130. std::wstring ToWString(const std::string & x) = delete; // Unknown encoding.
  131. std::wstring ToWString(const char * const & x) = delete; // Unknown encoding. Note that this also applies to TCHAR in !UNICODE builds as the type is indistinguishable from char. Wrap with CString or FromTcharStr in this case.
  132. std::wstring ToWString(const char & x) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead
  133. inline std::wstring ToWString(const std::wstring & x) { return x; }
  134. inline std::wstring ToWString(const wchar_t * const & x) { return x; }
  135. std::wstring ToWString(const wchar_t & x) = delete; // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
  136. #if MPT_USTRING_MODE_UTF8
  137. std::wstring ToWString(const mpt::ustring & x);
  138. #endif
  139. #if defined(MPT_WITH_MFC)
  140. std::wstring ToWString(const CString & x);
  141. #endif // MPT_WITH_MFC
  142. std::wstring ToWString(const bool & x);
  143. std::wstring ToWString(const signed char & x);
  144. std::wstring ToWString(const unsigned char & x);
  145. std::wstring ToWString(const signed short & x);
  146. std::wstring ToWString(const unsigned short & x);
  147. std::wstring ToWString(const signed int & x);
  148. std::wstring ToWString(const unsigned int & x);
  149. std::wstring ToWString(const signed long & x);
  150. std::wstring ToWString(const unsigned long & x);
  151. std::wstring ToWString(const signed long long & x);
  152. std::wstring ToWString(const unsigned long long & x);
  153. std::wstring ToWString(const float & x);
  154. std::wstring ToWString(const double & x);
  155. std::wstring ToWString(const long double & x);
  156. // fallback to member function ToUString()
  157. template <typename T> auto ToWString(const T & x) -> decltype(mpt::ToWide(x.ToUString())) { return mpt::ToWide(x.ToUString()); }
  158. #endif
  159. #if defined(MPT_ENABLE_CHARSET_LOCALE)
  160. template <typename T> struct ToLocaleHelper { mpt::lstring operator () (const T & v) { return mpt::ToLocale(ToUString(v)); } };
  161. template <> struct ToLocaleHelper<mpt::lstring> { mpt::lstring operator () (const mpt::lstring & v) { return v; } };
  162. #endif // MPT_ENABLE_CHARSET_LOCALE
  163. #if defined(MPT_WITH_MFC)
  164. template <typename T> struct ToCStringHelper { CString operator () (const T & v) { return mpt::ToCString(ToUString(v)); } };
  165. template <> struct ToCStringHelper<CString> { CString operator () (const CString & v) { return v; } };
  166. #endif // MPT_WITH_MFC
  167. template <typename Tstring> struct ToStringTFunctor {};
  168. template <> struct ToStringTFunctor<std::string> { template <typename T> inline std::string operator() (const T & x) { return ToAString(x); } };
  169. template <> struct ToStringTFunctor<mpt::ustring> { template <typename T> inline mpt::ustring operator() (const T & x) { return ToUString(x); } };
  170. #if MPT_WSTRING_FORMAT && MPT_USTRING_MODE_UTF8
  171. template <> struct ToStringTFunctor<std::wstring> { template <typename T> inline std::wstring operator() (const T & x) { return ToWString(x); } };
  172. #endif
  173. #if defined(MPT_ENABLE_CHARSET_LOCALE)
  174. template <> struct ToStringTFunctor<mpt::lstring> { template <typename T> inline mpt::lstring operator() (const T & x) { return mpt::ToLocaleHelper<T>()(x); } };
  175. #endif // MPT_ENABLE_CHARSET_LOCALE
  176. #if defined(MPT_WITH_MFC)
  177. template <> struct ToStringTFunctor<CString> { template <typename T> inline CString operator() (const T & x) { return mpt::ToCStringHelper<T>()(x); } };
  178. #endif // MPT_WITH_MFC
  179. template<typename Tstring, typename T> inline Tstring ToStringT(const T & x) { return ToStringTFunctor<Tstring>()(x); }
  180. struct ToStringFormatter {
  181. template <typename Tstring, typename T>
  182. static inline Tstring format(const T& value) {
  183. return ToStringTFunctor<Tstring>()(value);
  184. }
  185. };
  186. using FormatSpec = mpt::format_simple_spec;
  187. using FormatFlags = mpt::format_simple_flags;
  188. using fmt_base = mpt::format_simple_base;
  189. std::string FormatValA(const char & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead
  190. #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
  191. std::string FormatValA(const wchar_t & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
  192. #endif // !MPT_COMPILER_QUIRK_NO_WCHAR
  193. std::string FormatValA(const bool & x, const FormatSpec & f);
  194. std::string FormatValA(const signed char & x, const FormatSpec & f);
  195. std::string FormatValA(const unsigned char & x, const FormatSpec & f);
  196. std::string FormatValA(const signed short & x, const FormatSpec & f);
  197. std::string FormatValA(const unsigned short & x, const FormatSpec & f);
  198. std::string FormatValA(const signed int & x, const FormatSpec & f);
  199. std::string FormatValA(const unsigned int & x, const FormatSpec & f);
  200. std::string FormatValA(const signed long & x, const FormatSpec & f);
  201. std::string FormatValA(const unsigned long & x, const FormatSpec & f);
  202. std::string FormatValA(const signed long long & x, const FormatSpec & f);
  203. std::string FormatValA(const unsigned long long & x, const FormatSpec & f);
  204. std::string FormatValA(const float & x, const FormatSpec & f);
  205. std::string FormatValA(const double & x, const FormatSpec & f);
  206. std::string FormatValA(const long double & x, const FormatSpec & f);
  207. mpt::ustring FormatValU(const char & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead
  208. #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
  209. mpt::ustring FormatValU(const wchar_t & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
  210. #endif // !MPT_COMPILER_QUIRK_NO_WCHAR
  211. mpt::ustring FormatValU(const bool & x, const FormatSpec & f);
  212. mpt::ustring FormatValU(const signed char & x, const FormatSpec & f);
  213. mpt::ustring FormatValU(const unsigned char & x, const FormatSpec & f);
  214. mpt::ustring FormatValU(const signed short & x, const FormatSpec & f);
  215. mpt::ustring FormatValU(const unsigned short & x, const FormatSpec & f);
  216. mpt::ustring FormatValU(const signed int & x, const FormatSpec & f);
  217. mpt::ustring FormatValU(const unsigned int & x, const FormatSpec & f);
  218. mpt::ustring FormatValU(const signed long & x, const FormatSpec & f);
  219. mpt::ustring FormatValU(const unsigned long & x, const FormatSpec & f);
  220. mpt::ustring FormatValU(const signed long long & x, const FormatSpec & f);
  221. mpt::ustring FormatValU(const unsigned long long & x, const FormatSpec & f);
  222. mpt::ustring FormatValU(const float & x, const FormatSpec & f);
  223. mpt::ustring FormatValU(const double & x, const FormatSpec & f);
  224. mpt::ustring FormatValU(const long double & x, const FormatSpec & f);
  225. #if MPT_WSTRING_FORMAT
  226. std::wstring FormatValW(const char & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead
  227. #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
  228. std::wstring FormatValW(const wchar_t & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
  229. #endif // !MPT_COMPILER_QUIRK_NO_WCHAR
  230. std::wstring FormatValW(const bool & x, const FormatSpec & f);
  231. std::wstring FormatValW(const signed char & x, const FormatSpec & f);
  232. std::wstring FormatValW(const unsigned char & x, const FormatSpec & f);
  233. std::wstring FormatValW(const signed short & x, const FormatSpec & f);
  234. std::wstring FormatValW(const unsigned short & x, const FormatSpec & f);
  235. std::wstring FormatValW(const signed int & x, const FormatSpec & f);
  236. std::wstring FormatValW(const unsigned int & x, const FormatSpec & f);
  237. std::wstring FormatValW(const signed long & x, const FormatSpec & f);
  238. std::wstring FormatValW(const unsigned long & x, const FormatSpec & f);
  239. std::wstring FormatValW(const signed long long & x, const FormatSpec & f);
  240. std::wstring FormatValW(const unsigned long long & x, const FormatSpec & f);
  241. std::wstring FormatValW(const float & x, const FormatSpec & f);
  242. std::wstring FormatValW(const double & x, const FormatSpec & f);
  243. std::wstring FormatValW(const long double & x, const FormatSpec & f);
  244. #endif
  245. template <typename Tstring> struct FormatValTFunctor {};
  246. template <> struct FormatValTFunctor<std::string> { template <typename T> inline std::string operator() (const T & x, const FormatSpec & f) { return FormatValA(x, f); } };
  247. template <> struct FormatValTFunctor<mpt::ustring> { template <typename T> inline mpt::ustring operator() (const T & x, const FormatSpec & f) { return FormatValU(x, f); } };
  248. #if MPT_USTRING_MODE_UTF8 && MPT_WSTRING_FORMAT
  249. template <> struct FormatValTFunctor<std::wstring> { template <typename T> inline std::wstring operator() (const T & x, const FormatSpec & f) { return FormatValW(x, f); } };
  250. #endif
  251. #if defined(MPT_ENABLE_CHARSET_LOCALE)
  252. template <> struct FormatValTFunctor<mpt::lstring> { template <typename T> inline mpt::lstring operator() (const T & x, const FormatSpec & f) { return mpt::ToLocale(mpt::Charset::Locale, FormatValA(x, f)); } };
  253. #endif // MPT_ENABLE_CHARSET_LOCALE
  254. #if defined(MPT_WITH_MFC)
  255. #ifdef UNICODE
  256. template <> struct FormatValTFunctor<CString> { template <typename T> inline CString operator() (const T & x, const FormatSpec & f) { return mpt::ToCString(FormatValW(x, f)); } };
  257. #else // !UNICODE
  258. template <> struct FormatValTFunctor<CString> { template <typename T> inline CString operator() (const T & x, const FormatSpec & f) { return mpt::ToCString(mpt::Charset::Locale, FormatValA(x, f)); } };
  259. #endif // UNICODE
  260. #endif // MPT_WITH_MFC
  261. template <typename Tstring>
  262. struct fmtT : fmt_base
  263. {
  264. template<typename T>
  265. static inline Tstring val(const T& x)
  266. {
  267. return ToStringTFunctor<Tstring>()(x);
  268. }
  269. template<typename T>
  270. static inline Tstring fmt(const T& x, const FormatSpec& f)
  271. {
  272. return FormatValTFunctor<Tstring>()(x, f);
  273. }
  274. template<typename T>
  275. static inline Tstring dec(const T& x)
  276. {
  277. static_assert(std::numeric_limits<T>::is_integer);
  278. return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseDec().FillOff());
  279. }
  280. template<int width, typename T>
  281. static inline Tstring dec0(const T& x)
  282. {
  283. static_assert(std::numeric_limits<T>::is_integer);
  284. return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseDec().FillNul().Width(width));
  285. }
  286. template<typename T>
  287. static inline Tstring dec(unsigned int g, char s, const T& x)
  288. {
  289. static_assert(std::numeric_limits<T>::is_integer);
  290. return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseDec().FillOff().Group(g).GroupSep(s));
  291. }
  292. template<int width, typename T>
  293. static inline Tstring dec0(unsigned int g, char s, const T& x)
  294. {
  295. static_assert(std::numeric_limits<T>::is_integer);
  296. return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseDec().FillNul().Width(width).Group(g).GroupSep(s));
  297. }
  298. template<typename T>
  299. static inline Tstring hex(const T& x)
  300. {
  301. static_assert(std::numeric_limits<T>::is_integer);
  302. return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseLow().FillOff());
  303. }
  304. template<typename T>
  305. static inline Tstring HEX(const T& x)
  306. {
  307. static_assert(std::numeric_limits<T>::is_integer);
  308. return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseUpp().FillOff());
  309. }
  310. template<int width, typename T>
  311. static inline Tstring hex0(const T& x)
  312. {
  313. static_assert(std::numeric_limits<T>::is_integer);
  314. return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseLow().FillNul().Width(width));
  315. }
  316. template<int width, typename T>
  317. static inline Tstring HEX0(const T& x)
  318. {
  319. static_assert(std::numeric_limits<T>::is_integer);
  320. return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseUpp().FillNul().Width(width));
  321. }
  322. template<typename T>
  323. static inline Tstring hex(unsigned int g, char s, const T& x)
  324. {
  325. static_assert(std::numeric_limits<T>::is_integer);
  326. return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseLow().FillOff().Group(g).GroupSep(s));
  327. }
  328. template<typename T>
  329. static inline Tstring HEX(unsigned int g, char s, const T& x)
  330. {
  331. static_assert(std::numeric_limits<T>::is_integer);
  332. return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseUpp().FillOff().Group(g).GroupSep(s));
  333. }
  334. template<int width, typename T>
  335. static inline Tstring hex0(unsigned int g, char s, const T& x)
  336. {
  337. static_assert(std::numeric_limits<T>::is_integer);
  338. return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseLow().FillNul().Width(width).Group(g).GroupSep(s));
  339. }
  340. template<int width, typename T>
  341. static inline Tstring HEX0(unsigned int g, char s, const T& x)
  342. {
  343. static_assert(std::numeric_limits<T>::is_integer);
  344. return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseUpp().FillNul().Width(width).Group(g).GroupSep(s));
  345. }
  346. template<typename T>
  347. static inline Tstring flt(const T& x, int precision = -1)
  348. {
  349. static_assert(std::is_floating_point<T>::value);
  350. return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaNrm().FillOff().Precision(precision));
  351. }
  352. template<typename T>
  353. static inline Tstring fix(const T& x, int precision = -1)
  354. {
  355. static_assert(std::is_floating_point<T>::value);
  356. return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaFix().FillOff().Precision(precision));
  357. }
  358. template<typename T>
  359. static inline Tstring sci(const T& x, int precision = -1)
  360. {
  361. static_assert(std::is_floating_point<T>::value);
  362. return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaSci().FillOff().Precision(precision));
  363. }
  364. template<typename T>
  365. static inline Tstring ptr(const T& x)
  366. {
  367. static_assert(std::is_pointer<T>::value || std::is_same<T, std::uintptr_t>::value || std::is_same<T, std::intptr_t>::value, "");
  368. return hex0<mpt::pointer_size * 2>(mpt::pointer_cast<const std::uintptr_t>(x));
  369. }
  370. template<typename T>
  371. static inline Tstring PTR(const T& x)
  372. {
  373. static_assert(std::is_pointer<T>::value || std::is_same<T, std::uintptr_t>::value || std::is_same<T, std::intptr_t>::value, "");
  374. return HEX0<mpt::pointer_size * 2>(mpt::pointer_cast<const std::uintptr_t>(x));
  375. }
  376. static inline Tstring pad_left(std::size_t width_, const Tstring &str)
  377. {
  378. typedef mpt::string_traits<Tstring> traits;
  379. typename traits::size_type width = static_cast<typename traits::size_type>(width_);
  380. return traits::pad(str, width, 0);
  381. }
  382. static inline Tstring pad_right(std::size_t width_, const Tstring &str)
  383. {
  384. typedef mpt::string_traits<Tstring> traits;
  385. typename traits::size_type width = static_cast<typename traits::size_type>(width_);
  386. return traits::pad(str, 0, width);
  387. }
  388. static inline Tstring left(std::size_t width_, const Tstring &str)
  389. {
  390. typedef mpt::string_traits<Tstring> traits;
  391. typename traits::size_type width = static_cast<typename traits::size_type>(width_);
  392. return (traits::length(str) < width) ? traits::pad(str, 0, width - traits::length(str)) : str;
  393. }
  394. static inline Tstring right(std::size_t width_, const Tstring &str)
  395. {
  396. typedef mpt::string_traits<Tstring> traits;
  397. typename traits::size_type width = static_cast<typename traits::size_type>(width_);
  398. return (traits::length(str) < width) ? traits::pad(str, width - traits::length(str), 0) : str;
  399. }
  400. static inline Tstring center(std::size_t width_, const Tstring &str)
  401. {
  402. typedef mpt::string_traits<Tstring> traits;
  403. typename traits::size_type width = static_cast<typename traits::size_type>(width_);
  404. return (traits::length(str) < width) ? traits::pad(str, (width - traits::length(str)) / 2, (width - traits::length(str) + 1) / 2) : str;
  405. }
  406. }; // struct fmtT
  407. typedef fmtT<std::string> afmt;
  408. #if MPT_WSTRING_FORMAT
  409. typedef fmtT<std::wstring> wfmt;
  410. #endif
  411. #if MPT_USTRING_MODE_WIDE
  412. typedef fmtT<std::wstring> ufmt;
  413. #else
  414. typedef fmtT<mpt::ustring> ufmt;
  415. #endif
  416. #if defined(MPT_ENABLE_CHARSET_LOCALE)
  417. typedef fmtT<mpt::lstring> lfmt;
  418. #endif // MPT_ENABLE_CHARSET_LOCALE
  419. #if MPT_OS_WINDOWS
  420. typedef fmtT<mpt::tstring> tfmt;
  421. #endif
  422. #if defined(MPT_WITH_MFC)
  423. typedef fmtT<CString> cfmt;
  424. #endif // MPT_WITH_MFC
  425. #define MPT_AFORMAT(f) mpt::format_message<mpt::ToStringFormatter, mpt::parse_format_string_argument_count(f)>(f)
  426. #if MPT_WSTRING_FORMAT
  427. #define MPT_WFORMAT(f) mpt::format_message_typed<mpt::ToStringFormatter, mpt::parse_format_string_argument_count( L ## f ), std::wstring>( L ## f )
  428. #endif
  429. #define MPT_UFORMAT(f) mpt::format_message_typed<mpt::ToStringFormatter, mpt::parse_format_string_argument_count(MPT_ULITERAL(f)), mpt::ustring>(MPT_ULITERAL(f))
  430. #if defined(MPT_ENABLE_CHARSET_LOCALE)
  431. #define MPT_LFORMAT(f) mpt::format_message_typed<mpt::ToStringFormatter, mpt::parse_format_string_argument_count(f), mpt::lstring>(f)
  432. #endif // MPT_ENABLE_CHARSET_LOCALE
  433. #if MPT_OS_WINDOWS
  434. #define MPT_TFORMAT(f) mpt::format_message_typed<mpt::ToStringFormatter, mpt::parse_format_string_argument_count(TEXT(f)), mpt::tstring>(TEXT(f))
  435. #endif
  436. #if defined(MPT_WITH_MFC)
  437. #define MPT_CFORMAT(f) mpt::format_message_typed<mpt::ToStringFormatter, mpt::parse_format_string_argument_count(TEXT(f)), CString>(TEXT(f))
  438. #endif // MPT_WITH_MFC
  439. } // namespace mpt
  440. namespace mpt { namespace String {
  441. // Combine a vector of values into a string, separated with the given separator.
  442. // No escaping is performed.
  443. template<typename T>
  444. mpt::ustring Combine(const std::vector<T> &vals, const mpt::ustring &sep=U_(","))
  445. {
  446. mpt::ustring str;
  447. for(std::size_t i = 0; i < vals.size(); ++i)
  448. {
  449. if(i > 0)
  450. {
  451. str += sep;
  452. }
  453. str += mpt::ufmt::val(vals[i]);
  454. }
  455. return str;
  456. }
  457. template<typename T>
  458. std::string Combine(const std::vector<T> &vals, const std::string &sep=std::string(","))
  459. {
  460. std::string str;
  461. for(std::size_t i = 0; i < vals.size(); ++i)
  462. {
  463. if(i > 0)
  464. {
  465. str += sep;
  466. }
  467. str += mpt::afmt::val(vals[i]);
  468. }
  469. return str;
  470. }
  471. } } // namespace mpt::String
  472. template <typename enum_t, typename store_t>
  473. mpt::ustring ToUString(FlagSet<enum_t, store_t> flagset)
  474. {
  475. mpt::ustring str(flagset.size_bits(), UC_('0'));
  476. for(std::size_t x = 0; x < flagset.size_bits(); ++x)
  477. {
  478. str[flagset.size_bits() - x - 1] = (flagset.value().as_bits() & (static_cast<typename FlagSet<enum_t>::store_type>(1) << x) ? UC_('1') : UC_('0'));
  479. }
  480. return str;
  481. }
  482. OPENMPT_NAMESPACE_END