/* * mptStringFormat.h * ----------------- * Purpose: Convert other types to strings. * Notes : Currently none. * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #pragma once #include "BuildSettings.h" #include "mptString.h" OPENMPT_NAMESPACE_BEGIN // The following section demands a rationale. // 1. mpt::fmt::val(), mpt::wfmt::val() and mpt::ufmt::val() mimic the semantics of c++11 std::to_string() and std::to_wstring(). // There is an important difference though. The c++11 versions are specified in terms of sprintf formatting which in turn // depends on the current C locale. This renders these functions unusable in a library context because the current // C locale is set by the library-using application and could be anything. There is no way a library can get reliable semantics // out of these functions. It is thus better to just avoid them. // ToString() and ToWString() are based on iostream internally, but the the locale of the stream is forced to std::locale::classic(), // which results in "C" ASCII locale behavior. // 2. The full suite of printf-like or iostream like number formatting is generally not required. Instead, a sane subset functionality // is provided here. // For convenience, mpt::fmt::f(const char *, float) allows formatting a single floating point value with a // standard printf-like format string. This itself relies on iostream with classic() locale internally and is thus current locale // agnostic. // When formatting integers, it is recommended to use mpt::fmt::dec or mpt::fmt::hex. Appending a template argument '' sets the width, // 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' // in upper-case generates upper-case hex digits. If these are not known at compile-time, a more verbose FormatVal(int, format) can be // used. // 3. mpt::format(format)(...) provides simplified and type-safe message and localization string formatting. // The only specifier allowed is '%' followed by a single digit n. It references to n-th parameter after the format string (1-based). // This mimics the behaviour of QString::arg() in QT4/5 or MFC AfxFormatString2(). C printf-like functions offer similar functionality // with a '%n$TYPE' syntax. In .NET, the syntax is '{n}'. This is useful to support localization strings that can change the parameter // ordering. // 4. Every function is available for std::string, std::wstring and mpt::ustring. std::string makes no assumption about the encoding, which // basically means, it should work for any 7-bit or 8-bit encoding, including for example ASCII, UTF8 or the current locale encoding. // std::string std::wstring mpt::ustring mpt::tsrtring CString // mpt::fmt mpt::wfmt mpt::ufmt mpt::tfmt mpt::cfmt // mpt::format("%1") mpt::wformat(L"%1") mpt::uformat(MPT_ULITERAL(%1) mpt::tformat(_T("%1")) mpt::cformat(_T("%1")) // mpt::format("%1") mpt::format(L"%1") mpt::format(MPT_USTRING(%1)) mpt::format(mpt::tstring(_T("%1")) mpt::format(CString(_T("%1")) // 5. All functionality here delegates real work outside of the header file so that and do not need to be included when // using this functionality. // Advantages: // - Avoids binary code bloat when too much of iostream operator << gets inlined at every usage site. // - Faster compile times because and (2 very complex headers) are not included everywhere. // Disadvantages: // - Slightly more c++ code is required for delegating work. // - As the header does not use iostreams, custom types need to overload mpt::UString instead of iostream operator << to allow for custom type // formatting. // - std::string, std::wstring and mpt::ustring are returned from somewhat deep cascades of helper functions. Where possible, code is // written in such a way that return-value-optimization (RVO) or named-return-value-optimization (NRVO) should be able to eliminate // 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 // move-semantics will kick in if RVO/NRVO fails). namespace mpt { // ToUString() converts various built-in types to a well-defined, locale-independent string representation. // This is also used as a type-tunnel pattern for mpt::format. // Custom types that need to be converted to strings are encouraged to overload ToUString(). // fallback to member function ToUString() #if MPT_USTRING_MODE_UTF8 template auto ToString(const T & x) -> decltype(mpt::ToCharset(mpt::CharsetUTF8, x.ToUString())) { return mpt::ToCharset(mpt::CharsetUTF8, x.ToUString()); } #else template auto ToString(const T & x) -> decltype(mpt::ToCharset(mpt::CharsetLocaleOrUTF8, x.ToUString())) { return mpt::ToCharset(mpt::CharsetLocaleOrUTF8, x.ToUString()); } #endif static inline std::string ToString(const std::string & x) { return x; } static inline std::string ToString(const char * const & x) { return x; } MPT_DEPRECATED static inline std::string ToString(const char & x) { return std::string(1, x); } // deprecated to catch potential API mis-use, use std::string(1, x) instead #if MPT_WSTRING_FORMAT MPT_DEPRECATED std::string ToString(const std::wstring & x); // Unknown encoding. MPT_DEPRECATED std::string ToString(const wchar_t * const & x); // Unknown encoding. MPT_DEPRECATED std::string ToString(const wchar_t & x); // deprecated to catch potential API mis-use, use std::wstring(1, x) instead #endif #if MPT_USTRING_MODE_UTF8 MPT_DEPRECATED std::string ToString(const mpt::ustring & x); // Unknown encoding. #endif #if defined(_MFC_VER) MPT_DEPRECATED std::string ToString(const mpt::ustring & x); // Unknown encoding. #endif #if defined(_MFC_VER) MPT_DEPRECATED std::string ToString(const CString & x); #endif std::string ToString(const bool & x); std::string ToString(const signed char & x); std::string ToString(const unsigned char & x); std::string ToString(const signed short & x); std::string ToString(const unsigned short & x); std::string ToString(const signed int & x); std::string ToString(const unsigned int & x); std::string ToString(const signed long & x); std::string ToString(const unsigned long & x); std::string ToString(const signed long long & x); std::string ToString(const unsigned long long & x); std::string ToString(const float & x); std::string ToString(const double & x); std::string ToString(const long double & x); // fallback to member function ToUString() template auto ToUString(const T & x) -> decltype(x.ToUString()) { return x.ToUString(); } static inline mpt::ustring ToUString(const mpt::ustring & x) { return x; } MPT_DEPRECATED mpt::ustring ToUString(const std::string & x); // Unknown encoding. MPT_DEPRECATED mpt::ustring ToUString(const char * const & x); // 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. MPT_DEPRECATED mpt::ustring ToUString(const char & x); // deprecated to catch potential API mis-use, use std::string(1, x) instead #if MPT_WSTRING_FORMAT #if MPT_USTRING_MODE_UTF8 mpt::ustring ToUString(const std::wstring & x); #endif mpt::ustring ToUString(const wchar_t * const & x); MPT_DEPRECATED mpt::ustring ToUString(const wchar_t & x); // deprecated to catch potential API mis-use, use std::wstring(1, x) instead #endif #if defined(_MFC_VER) mpt::ustring ToUString(const CString & x); #endif mpt::ustring ToUString(const bool & x); mpt::ustring ToUString(const signed char & x); mpt::ustring ToUString(const unsigned char & x); mpt::ustring ToUString(const signed short & x); mpt::ustring ToUString(const unsigned short & x); mpt::ustring ToUString(const signed int & x); mpt::ustring ToUString(const unsigned int & x); mpt::ustring ToUString(const signed long & x); mpt::ustring ToUString(const unsigned long & x); mpt::ustring ToUString(const signed long long & x); mpt::ustring ToUString(const unsigned long long & x); mpt::ustring ToUString(const float & x); mpt::ustring ToUString(const double & x); mpt::ustring ToUString(const long double & x); #if MPT_WSTRING_FORMAT MPT_DEPRECATED std::wstring ToWString(const std::string & x); // Unknown encoding. MPT_DEPRECATED std::wstring ToWString(const char * const & x); // 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. MPT_DEPRECATED std::wstring ToWString(const char & x); // deprecated to catch potential API mis-use, use std::string(1, x) instead static inline std::wstring ToWString(const std::wstring & x) { return x; } static inline std::wstring ToWString(const wchar_t * const & x) { return x; } MPT_DEPRECATED static inline std::wstring ToWString(const wchar_t & x) { return std::wstring(1, x); } // deprecated to catch potential API mis-use, use std::wstring(1, x) instead #if MPT_USTRING_MODE_UTF8 std::wstring ToWString(const mpt::ustring & x); #endif #if defined(_MFC_VER) std::wstring ToWString(const CString & x); #endif std::wstring ToWString(const bool & x); std::wstring ToWString(const signed char & x); std::wstring ToWString(const unsigned char & x); std::wstring ToWString(const signed short & x); std::wstring ToWString(const unsigned short & x); std::wstring ToWString(const signed int & x); std::wstring ToWString(const unsigned int & x); std::wstring ToWString(const signed long & x); std::wstring ToWString(const unsigned long & x); std::wstring ToWString(const signed long long & x); std::wstring ToWString(const unsigned long long & x); std::wstring ToWString(const float & x); std::wstring ToWString(const double & x); std::wstring ToWString(const long double & x); // fallback to member function ToUString() template auto ToWString(const T & x) -> decltype(mpt::ToWide(x.ToUString())) { return mpt::ToWide(x.ToUString()); } #endif #if defined(MPT_ENABLE_CHARSET_LOCALE) template struct ToLocaleHelper { mpt::lstring operator () (const T & v) { return mpt::ToLocale(ToUString(v)); } }; template <> struct ToLocaleHelper { mpt::lstring operator () (const mpt::lstring & v) { return v; } }; #endif // MPT_ENABLE_CHARSET_LOCALE #if defined(_MFC_VER) template struct ToCStringHelper { CString operator () (const T & v) { return mpt::ToCString(ToUString(v)); } }; template <> struct ToCStringHelper { CString operator () (const CString & v) { return v; } }; #endif template struct ToStringTFunctor {}; template <> struct ToStringTFunctor { template inline std::string operator() (const T & x) { return ToString(x); } }; template <> struct ToStringTFunctor { template inline mpt::ustring operator() (const T & x) { return ToUString(x); } }; #if MPT_WSTRING_FORMAT && MPT_USTRING_MODE_UTF8 template <> struct ToStringTFunctor { template inline std::wstring operator() (const T & x) { return ToWString(x); } }; #endif #if defined(MPT_ENABLE_CHARSET_LOCALE) template <> struct ToStringTFunctor { template inline mpt::lstring operator() (const T & x) { return mpt::ToLocaleHelper()(x); } }; #endif // MPT_ENABLE_CHARSET_LOCALE #if defined(_MFC_VER) template <> struct ToStringTFunctor { template inline CString operator() (const T & x) { return mpt::ToCStringHelper()(x); } }; #endif template inline Tstring ToStringT(const T & x) { return ToStringTFunctor()(x); } struct fmt_base { enum FormatFlagsEnum { BaseDec = 0x0001, // base 10 (integers only) BaseHex = 0x0002, // base 16 (integers only) CaseLow = 0x0010, // lower case hex digits CaseUpp = 0x0020, // upper case hex digits FillOff = 0x0100, // do not fill up width FillNul = 0x0400, // fill up width with zeros NotaNrm = 0x1000, // float: normal/default notation NotaFix = 0x2000, // float: fixed point notation NotaSci = 0x4000, // float: scientific notation }; }; // struct fmt_base typedef unsigned int FormatFlags; STATIC_ASSERT(sizeof(FormatFlags) >= sizeof(fmt_base::FormatFlagsEnum)); class FormatSpec; MPT_DEPRECATED std::string FormatVal(const char & x, const FormatSpec & f); // deprecated to catch potential API mis-use, use std::string(1, x) instead #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) MPT_DEPRECATED std::string FormatVal(const wchar_t & x, const FormatSpec & f); // deprecated to catch potential API mis-use, use std::wstring(1, x) instead #endif // !MPT_COMPILER_QUIRK_NO_WCHAR std::string FormatVal(const bool & x, const FormatSpec & f); std::string FormatVal(const signed char & x, const FormatSpec & f); std::string FormatVal(const unsigned char & x, const FormatSpec & f); std::string FormatVal(const signed short & x, const FormatSpec & f); std::string FormatVal(const unsigned short & x, const FormatSpec & f); std::string FormatVal(const signed int & x, const FormatSpec & f); std::string FormatVal(const unsigned int & x, const FormatSpec & f); std::string FormatVal(const signed long & x, const FormatSpec & f); std::string FormatVal(const unsigned long & x, const FormatSpec & f); std::string FormatVal(const signed long long & x, const FormatSpec & f); std::string FormatVal(const unsigned long long & x, const FormatSpec & f); std::string FormatVal(const float & x, const FormatSpec & f); std::string FormatVal(const double & x, const FormatSpec & f); std::string FormatVal(const long double & x, const FormatSpec & f); MPT_DEPRECATED mpt::ustring FormatValU(const char & x, const FormatSpec & f); // deprecated to catch potential API mis-use, use std::string(1, x) instead #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) MPT_DEPRECATED mpt::ustring FormatValU(const wchar_t & x, const FormatSpec & f); // deprecated to catch potential API mis-use, use std::wstring(1, x) instead #endif // !MPT_COMPILER_QUIRK_NO_WCHAR mpt::ustring FormatValU(const bool & x, const FormatSpec & f); mpt::ustring FormatValU(const signed char & x, const FormatSpec & f); mpt::ustring FormatValU(const unsigned char & x, const FormatSpec & f); mpt::ustring FormatValU(const signed short & x, const FormatSpec & f); mpt::ustring FormatValU(const unsigned short & x, const FormatSpec & f); mpt::ustring FormatValU(const signed int & x, const FormatSpec & f); mpt::ustring FormatValU(const unsigned int & x, const FormatSpec & f); mpt::ustring FormatValU(const signed long & x, const FormatSpec & f); mpt::ustring FormatValU(const unsigned long & x, const FormatSpec & f); mpt::ustring FormatValU(const signed long long & x, const FormatSpec & f); mpt::ustring FormatValU(const unsigned long long & x, const FormatSpec & f); mpt::ustring FormatValU(const float & x, const FormatSpec & f); mpt::ustring FormatValU(const double & x, const FormatSpec & f); mpt::ustring FormatValU(const long double & x, const FormatSpec & f); #if MPT_WSTRING_FORMAT MPT_DEPRECATED std::wstring FormatValW(const char & x, const FormatSpec & f); // deprecated to catch potential API mis-use, use std::string(1, x) instead #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) MPT_DEPRECATED std::wstring FormatValW(const wchar_t & x, const FormatSpec & f); // deprecated to catch potential API mis-use, use std::wstring(1, x) instead #endif // !MPT_COMPILER_QUIRK_NO_WCHAR std::wstring FormatValW(const bool & x, const FormatSpec & f); std::wstring FormatValW(const signed char & x, const FormatSpec & f); std::wstring FormatValW(const unsigned char & x, const FormatSpec & f); std::wstring FormatValW(const signed short & x, const FormatSpec & f); std::wstring FormatValW(const unsigned short & x, const FormatSpec & f); std::wstring FormatValW(const signed int & x, const FormatSpec & f); std::wstring FormatValW(const unsigned int & x, const FormatSpec & f); std::wstring FormatValW(const signed long & x, const FormatSpec & f); std::wstring FormatValW(const unsigned long & x, const FormatSpec & f); std::wstring FormatValW(const signed long long & x, const FormatSpec & f); std::wstring FormatValW(const unsigned long long & x, const FormatSpec & f); std::wstring FormatValW(const float & x, const FormatSpec & f); std::wstring FormatValW(const double & x, const FormatSpec & f); std::wstring FormatValW(const long double & x, const FormatSpec & f); #endif template struct FormatValTFunctor {}; template <> struct FormatValTFunctor { template inline std::string operator() (const T & x, const FormatSpec & f) { return FormatVal(x, f); } }; template <> struct FormatValTFunctor { template inline mpt::ustring operator() (const T & x, const FormatSpec & f) { return FormatValU(x, f); } }; #if MPT_USTRING_MODE_UTF8 && MPT_WSTRING_FORMAT template <> struct FormatValTFunctor { template inline std::wstring operator() (const T & x, const FormatSpec & f) { return FormatValW(x, f); } }; #endif #if defined(MPT_ENABLE_CHARSET_LOCALE) template <> struct FormatValTFunctor { template inline mpt::lstring operator() (const T & x, const FormatSpec & f) { return mpt::ToLocale(mpt::CharsetLocale, FormatVal(x, f)); } }; #endif // MPT_ENABLE_CHARSET_LOCALE #if defined(_MFC_VER) #ifdef UNICODE template <> struct FormatValTFunctor { template inline CString operator() (const T & x, const FormatSpec & f) { return mpt::ToCString(FormatValW(x, f)); } }; #else template <> struct FormatValTFunctor { template inline CString operator() (const T & x, const FormatSpec & f) { return mpt::ToCString(mpt::CharsetLocale, FormatVal(x, f)); } }; #endif #endif class FormatSpec { private: FormatFlags flags; std::size_t width; int precision; unsigned int group; char group_sep; public: MPT_CONSTEXPR11_FUN FormatSpec() noexcept : flags(0), width(0), precision(-1), group(0), group_sep(',') {} MPT_CONSTEXPR11_FUN FormatFlags GetFlags() const noexcept { return flags; } MPT_CONSTEXPR11_FUN std::size_t GetWidth() const noexcept { return width; } MPT_CONSTEXPR11_FUN int GetPrecision() const noexcept { return precision; } MPT_CONSTEXPR11_FUN unsigned int GetGroup() const noexcept { return group; } MPT_CONSTEXPR11_FUN char GetGroupSep() const noexcept { return group_sep; } MPT_CONSTEXPR14_FUN FormatSpec & SetFlags(FormatFlags f) noexcept { flags = f; return *this; } MPT_CONSTEXPR14_FUN FormatSpec & SetWidth(std::size_t w) noexcept { width = w; return *this; } MPT_CONSTEXPR14_FUN FormatSpec & SetPrecision(int p) noexcept { precision = p; return *this; } MPT_CONSTEXPR14_FUN FormatSpec & SetGroup(unsigned int g) noexcept { group = g; return *this; } MPT_CONSTEXPR14_FUN FormatSpec & SetGroupSep(char s) noexcept { group_sep = s; return *this; } public: MPT_CONSTEXPR14_FUN FormatSpec & BaseDec() noexcept { flags &= ~(fmt_base::BaseDec|fmt_base::BaseHex); flags |= fmt_base::BaseDec; return *this; } MPT_CONSTEXPR14_FUN FormatSpec & BaseHex() noexcept { flags &= ~(fmt_base::BaseDec|fmt_base::BaseHex); flags |= fmt_base::BaseHex; return *this; } MPT_CONSTEXPR14_FUN FormatSpec & CaseLow() noexcept { flags &= ~(fmt_base::CaseLow|fmt_base::CaseUpp); flags |= fmt_base::CaseLow; return *this; } MPT_CONSTEXPR14_FUN FormatSpec & CaseUpp() noexcept { flags &= ~(fmt_base::CaseLow|fmt_base::CaseUpp); flags |= fmt_base::CaseUpp; return *this; } MPT_CONSTEXPR14_FUN FormatSpec & FillOff() noexcept { flags &= ~(fmt_base::FillOff|fmt_base::FillNul); flags |= fmt_base::FillOff; return *this; } MPT_CONSTEXPR14_FUN FormatSpec & FillNul() noexcept { flags &= ~(fmt_base::FillOff|fmt_base::FillNul); flags |= fmt_base::FillNul; return *this; } MPT_CONSTEXPR14_FUN FormatSpec & NotaNrm() noexcept { flags &= ~(fmt_base::NotaNrm|fmt_base::NotaFix|fmt_base::NotaSci); flags |= fmt_base::NotaNrm; return *this; } MPT_CONSTEXPR14_FUN FormatSpec & NotaFix() noexcept { flags &= ~(fmt_base::NotaNrm|fmt_base::NotaFix|fmt_base::NotaSci); flags |= fmt_base::NotaFix; return *this; } MPT_CONSTEXPR14_FUN FormatSpec & NotaSci() noexcept { flags &= ~(fmt_base::NotaNrm|fmt_base::NotaFix|fmt_base::NotaSci); flags |= fmt_base::NotaSci; return *this; } MPT_CONSTEXPR14_FUN FormatSpec & Width(std::size_t w) noexcept { width = w; return *this; } MPT_CONSTEXPR14_FUN FormatSpec & Prec(int p) noexcept { precision = p; return *this; } MPT_CONSTEXPR14_FUN FormatSpec & Group(unsigned int g) noexcept { group = g; return *this; } MPT_CONSTEXPR14_FUN FormatSpec & GroupSep(char s) noexcept { group_sep = s; return *this; } public: MPT_CONSTEXPR14_FUN FormatSpec & Dec() noexcept { return BaseDec(); } MPT_CONSTEXPR14_FUN FormatSpec & Hex() noexcept { return BaseHex(); } MPT_CONSTEXPR14_FUN FormatSpec & Low() noexcept { return CaseLow(); } MPT_CONSTEXPR14_FUN FormatSpec & Upp() noexcept { return CaseUpp(); } MPT_CONSTEXPR14_FUN FormatSpec & Off() noexcept { return FillOff(); } MPT_CONSTEXPR14_FUN FormatSpec & Nul() noexcept { return FillNul(); } MPT_CONSTEXPR14_FUN FormatSpec & Nrm() noexcept { return NotaNrm(); } MPT_CONSTEXPR14_FUN FormatSpec & Fix() noexcept { return NotaFix(); } MPT_CONSTEXPR14_FUN FormatSpec & Sci() noexcept { return NotaSci(); } public: MPT_CONSTEXPR14_FUN FormatSpec & Decimal() noexcept { return BaseDec(); } MPT_CONSTEXPR14_FUN FormatSpec & Hexadecimal() noexcept { return BaseHex(); } MPT_CONSTEXPR14_FUN FormatSpec & Lower() noexcept { return CaseLow(); } MPT_CONSTEXPR14_FUN FormatSpec & Upper() noexcept { return CaseUpp(); } MPT_CONSTEXPR14_FUN FormatSpec & FillNone() noexcept { return FillOff(); } MPT_CONSTEXPR14_FUN FormatSpec & FillZero() noexcept { return FillNul(); } MPT_CONSTEXPR14_FUN FormatSpec & FloatNormal() noexcept { return NotaNrm(); } MPT_CONSTEXPR14_FUN FormatSpec & FloatFixed() noexcept { return NotaFix(); } MPT_CONSTEXPR14_FUN FormatSpec & FloatScientific() noexcept { return NotaSci(); } MPT_CONSTEXPR14_FUN FormatSpec & Precision(int p) noexcept { return Prec(p); } }; template struct fmtT : fmt_base { template static inline Tstring val(const T& x) { return ToStringTFunctor()(x); } template static inline Tstring fmt(const T& x, const FormatSpec& f) { return FormatValTFunctor()(x, f); } template static inline Tstring dec(const T& x) { STATIC_ASSERT(std::numeric_limits::is_integer); return FormatValTFunctor()(x, FormatSpec().BaseDec().FillOff()); } template static inline Tstring dec0(const T& x) { STATIC_ASSERT(std::numeric_limits::is_integer); return FormatValTFunctor()(x, FormatSpec().BaseDec().FillNul().Width(width)); } template static inline Tstring dec(unsigned int g, char s, const T& x) { STATIC_ASSERT(std::numeric_limits::is_integer); return FormatValTFunctor()(x, FormatSpec().BaseDec().FillOff().Group(g).GroupSep(s)); } template static inline Tstring dec0(unsigned int g, char s, const T& x) { STATIC_ASSERT(std::numeric_limits::is_integer); return FormatValTFunctor()(x, FormatSpec().BaseDec().FillNul().Width(width).Group(g).GroupSep(s)); } template static inline Tstring hex(const T& x) { STATIC_ASSERT(std::numeric_limits::is_integer); return FormatValTFunctor()(x, FormatSpec().BaseHex().CaseLow().FillOff()); } template static inline Tstring HEX(const T& x) { STATIC_ASSERT(std::numeric_limits::is_integer); return FormatValTFunctor()(x, FormatSpec().BaseHex().CaseUpp().FillOff()); } template static inline Tstring hex0(const T& x) { STATIC_ASSERT(std::numeric_limits::is_integer); return FormatValTFunctor()(x, FormatSpec().BaseHex().CaseLow().FillNul().Width(width)); } template static inline Tstring HEX0(const T& x) { STATIC_ASSERT(std::numeric_limits::is_integer); return FormatValTFunctor()(x, FormatSpec().BaseHex().CaseUpp().FillNul().Width(width)); } template static inline Tstring hex(unsigned int g, char s, const T& x) { STATIC_ASSERT(std::numeric_limits::is_integer); return FormatValTFunctor()(x, FormatSpec().BaseHex().CaseLow().FillOff().Group(g).GroupSep(s)); } template static inline Tstring HEX(unsigned int g, char s, const T& x) { STATIC_ASSERT(std::numeric_limits::is_integer); return FormatValTFunctor()(x, FormatSpec().BaseHex().CaseUpp().FillOff().Group(g).GroupSep(s)); } template static inline Tstring hex0(unsigned int g, char s, const T& x) { STATIC_ASSERT(std::numeric_limits::is_integer); return FormatValTFunctor()(x, FormatSpec().BaseHex().CaseLow().FillNul().Width(width).Group(g).GroupSep(s)); } template static inline Tstring HEX0(unsigned int g, char s, const T& x) { STATIC_ASSERT(std::numeric_limits::is_integer); return FormatValTFunctor()(x, FormatSpec().BaseHex().CaseUpp().FillNul().Width(width).Group(g).GroupSep(s)); } template static inline Tstring flt(const T& x, int precision = -1) { STATIC_ASSERT(std::is_floating_point::value); return FormatValTFunctor()(x, FormatSpec().NotaNrm().FillOff().Precision(precision)); } template static inline Tstring fix(const T& x, int precision = -1) { STATIC_ASSERT(std::is_floating_point::value); return FormatValTFunctor()(x, FormatSpec().NotaFix().FillOff().Precision(precision)); } template static inline Tstring sci(const T& x, int precision = -1) { STATIC_ASSERT(std::is_floating_point::value); return FormatValTFunctor()(x, FormatSpec().NotaSci().FillOff().Precision(precision)); } static inline Tstring pad_left(std::size_t width_, const Tstring &str) { typedef mpt::string_traits traits; typename traits::size_type width = static_cast(width_); return traits::pad(str, width, 0); } static inline Tstring pad_right(std::size_t width_, const Tstring &str) { typedef mpt::string_traits traits; typename traits::size_type width = static_cast(width_); return traits::pad(str, 0, width); } static inline Tstring left(std::size_t width_, const Tstring &str) { typedef mpt::string_traits traits; typename traits::size_type width = static_cast(width_); return (traits::length(str) < width) ? traits::pad(str, 0, width - traits::length(str)) : str; } static inline Tstring right(std::size_t width_, const Tstring &str) { typedef mpt::string_traits traits; typename traits::size_type width = static_cast(width_); return (traits::length(str) < width) ? traits::pad(str, width - traits::length(str), 0) : str; } static inline Tstring center(std::size_t width_, const Tstring &str) { typedef mpt::string_traits traits; typename traits::size_type width = static_cast(width_); return (traits::length(str) < width) ? traits::pad(str, (width - traits::length(str)) / 2, (width - traits::length(str) + 1) / 2) : str; } }; // struct fmtT typedef fmtT fmt; #if MPT_WSTRING_FORMAT typedef fmtT wfmt; #endif #if MPT_USTRING_MODE_WIDE typedef fmtT ufmt; #else typedef fmtT ufmt; #endif #if defined(MPT_ENABLE_CHARSET_LOCALE) typedef fmtT lfmt; #endif // MPT_ENABLE_CHARSET_LOCALE #if MPT_OS_WINDOWS typedef fmtT tfmt; #endif #if defined(_MFC_VER) typedef fmtT cfmt; #endif } // namespace mpt namespace mpt { namespace String { namespace detail { template struct to_string_type { }; template <> struct to_string_type { typedef std::string type; }; template <> struct to_string_type { typedef std::string type; }; template <> struct to_string_type { typedef std::string type; }; template <> struct to_string_type { typedef std::string type; }; template <> struct to_string_type { typedef std::string type; }; #if !defined(MPT_COMPILER_QUIRK_NO_WCHAR) template <> struct to_string_type { typedef std::wstring type; }; template <> struct to_string_type { typedef std::wstring type; }; template <> struct to_string_type { typedef std::wstring type; }; template <> struct to_string_type { typedef std::wstring type; }; template <> struct to_string_type { typedef std::wstring type; }; #endif // !MPT_COMPILER_QUIRK_NO_WCHAR #if MPT_USTRING_MODE_UTF8 template <> struct to_string_type { typedef mpt::ustring type; }; #endif #if defined(MPT_ENABLE_CHARSET_LOCALE) template <> struct to_string_type { typedef mpt::lstring type; }; #endif // MPT_ENABLE_CHARSET_LOCALE #if defined(_MFC_VER) template <> struct to_string_type { typedef CString type; }; #endif template struct to_string_type { typedef typename to_string_type::type type; }; std::string PrintImpl(const std::string & format , const std::string & x1 = std::string() , const std::string & x2 = std::string() , const std::string & x3 = std::string() , const std::string & x4 = std::string() , const std::string & x5 = std::string() , const std::string & x6 = std::string() , const std::string & x7 = std::string() , const std::string & x8 = std::string() ); #if MPT_WSTRING_FORMAT std::wstring PrintImpl(const std::wstring & format , const std::wstring & x1 = std::wstring() , const std::wstring & x2 = std::wstring() , const std::wstring & x3 = std::wstring() , const std::wstring & x4 = std::wstring() , const std::wstring & x5 = std::wstring() , const std::wstring & x6 = std::wstring() , const std::wstring & x7 = std::wstring() , const std::wstring & x8 = std::wstring() ); #endif #if MPT_USTRING_MODE_UTF8 mpt::ustring PrintImpl(const mpt::ustring & format , const mpt::ustring & x1 = mpt::ustring() , const mpt::ustring & x2 = mpt::ustring() , const mpt::ustring & x3 = mpt::ustring() , const mpt::ustring & x4 = mpt::ustring() , const mpt::ustring & x5 = mpt::ustring() , const mpt::ustring & x6 = mpt::ustring() , const mpt::ustring & x7 = mpt::ustring() , const mpt::ustring & x8 = mpt::ustring() ); #endif #if defined(MPT_ENABLE_CHARSET_LOCALE) mpt::lstring PrintImpl(const mpt::lstring & format , const mpt::lstring & x1 = mpt::lstring() , const mpt::lstring & x2 = mpt::lstring() , const mpt::lstring & x3 = mpt::lstring() , const mpt::lstring & x4 = mpt::lstring() , const mpt::lstring & x5 = mpt::lstring() , const mpt::lstring & x6 = mpt::lstring() , const mpt::lstring & x7 = mpt::lstring() , const mpt::lstring & x8 = mpt::lstring() ); #endif // MPT_ENABLE_CHARSET_LOCALE #if defined(_MFC_VER) CString PrintImpl(const CString & format , const CString & x1 = CString() , const CString & x2 = CString() , const CString & x3 = CString() , const CString & x4 = CString() , const CString & x5 = CString() , const CString & x6 = CString() , const CString & x7 = CString() , const CString & x8 = CString() ); #endif } // namespace detail } // namespace String template struct message_formatter { typedef typename mpt::String::detail::to_string_type::type Tstring; Tstring format; message_formatter(const Tstring & format) : format(format) {} Tstring operator() ( ) const { return mpt::String::detail::PrintImpl(format ); } template< typename T1 > Tstring operator() ( const T1& x1 ) const { return mpt::String::detail::PrintImpl(format , ToStringTFunctor()(x1) ); } template< typename T1 , typename T2 > Tstring operator() ( const T1& x1 , const T2& x2 ) const { return mpt::String::detail::PrintImpl(format , ToStringTFunctor()(x1) , ToStringTFunctor()(x2) ); } template< typename T1 , typename T2 , typename T3 > Tstring operator() ( const T1& x1 , const T2& x2 , const T3& x3 ) const { return mpt::String::detail::PrintImpl(format , ToStringTFunctor()(x1) , ToStringTFunctor()(x2) , ToStringTFunctor()(x3) ); } template< typename T1 , typename T2 , typename T3 , typename T4 > Tstring operator() ( const T1& x1 , const T2& x2 , const T3& x3 , const T4& x4 ) const { return mpt::String::detail::PrintImpl(format , ToStringTFunctor()(x1) , ToStringTFunctor()(x2) , ToStringTFunctor()(x3) , ToStringTFunctor()(x4) ); } template< typename T1 , typename T2 , typename T3 , typename T4 , typename T5 > Tstring operator() ( const T1& x1 , const T2& x2 , const T3& x3 , const T4& x4 , const T5& x5 ) const { return mpt::String::detail::PrintImpl(format , ToStringTFunctor()(x1) , ToStringTFunctor()(x2) , ToStringTFunctor()(x3) , ToStringTFunctor()(x4) , ToStringTFunctor()(x5) ); } template< typename T1 , typename T2 , typename T3 , typename T4 , typename T5 , typename T6 > Tstring operator() ( const T1& x1 , const T2& x2 , const T3& x3 , const T4& x4 , const T5& x5 , const T6& x6 ) const { return mpt::String::detail::PrintImpl(format , ToStringTFunctor()(x1) , ToStringTFunctor()(x2) , ToStringTFunctor()(x3) , ToStringTFunctor()(x4) , ToStringTFunctor()(x5) , ToStringTFunctor()(x6) ); } template< typename T1 , typename T2 , typename T3 , typename T4 , typename T5 , typename T6 , typename T7 > Tstring operator() ( const T1& x1 , const T2& x2 , const T3& x3 , const T4& x4 , const T5& x5 , const T6& x6 , const T7& x7 ) const { return mpt::String::detail::PrintImpl(format , ToStringTFunctor()(x1) , ToStringTFunctor()(x2) , ToStringTFunctor()(x3) , ToStringTFunctor()(x4) , ToStringTFunctor()(x5) , ToStringTFunctor()(x6) , ToStringTFunctor()(x7) ); } template< typename T1 , typename T2 , typename T3 , typename T4 , typename T5 , typename T6 , typename T7 , typename T8 > Tstring operator() ( const T1& x1 , const T2& x2 , const T3& x3 , const T4& x4 , const T5& x5 , const T6& x6 , const T7& x7 , const T8& x8 ) const { return mpt::String::detail::PrintImpl(format , ToStringTFunctor()(x1) , ToStringTFunctor()(x2) , ToStringTFunctor()(x3) , ToStringTFunctor()(x4) , ToStringTFunctor()(x5) , ToStringTFunctor()(x6) , ToStringTFunctor()(x7) , ToStringTFunctor()(x8) ); } }; // struct message_formatter template message_formatter::type> format(const Tformat &format) { typedef typename mpt::String::detail::to_string_type::type Tstring; return message_formatter(Tstring(format)); } #if MPT_WSTRING_FORMAT static inline message_formatter wformat(const std::wstring &format) { return message_formatter(format); } #endif static inline message_formatter uformat(const mpt::ustring &format) { return message_formatter(format); } #if defined(MPT_ENABLE_CHARSET_LOCALE) static inline message_formatter lformat(const mpt::lstring &format) { return message_formatter(format); } #endif // MPT_ENABLE_CHARSET_LOCALE #if MPT_OS_WINDOWS static inline message_formatter tformat(const mpt::tstring &format) { return message_formatter(format); } #endif #if defined(_MFC_VER) static inline message_formatter cformat(const CString &format) { return message_formatter(format); } #endif } // namespace mpt namespace mpt { namespace String { // Combine a vector of values into a string, separated with the given separator. // No escaping is performed. template mpt::ustring Combine(const std::vector &vals, const mpt::ustring &sep=U_(",")) { mpt::ustring str; for(std::size_t i = 0; i < vals.size(); ++i) { if(i > 0) { str += sep; } str += mpt::ufmt::val(vals[i]); } return str; } template std::string Combine(const std::vector &vals, const std::string &sep=std::string(",")) { std::string str; for(std::size_t i = 0; i < vals.size(); ++i) { if(i > 0) { str += sep; } str += mpt::fmt::val(vals[i]); } return str; } } } // namespace mpt::String OPENMPT_NAMESPACE_END