Bundle libOpenMPT as a dynamic framework, which should be safe once again, now that there is only one version to bundle. Also, now it is using the versions of libvorbisfile and libmpg123 that are bundled with the player, instead of compiling minimp3 and stbvorbis. Signed-off-by: Christopher Snowhill <kode54@gmail.com>
554 lines
26 KiB
C++
554 lines
26 KiB
C++
/*
|
|
* 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 "openmpt/all/BuildSettings.hpp"
|
|
|
|
#include "mpt/base/pointer.hpp"
|
|
#include "mpt/format/message.hpp"
|
|
#include "mpt/format/simple_spec.hpp"
|
|
#include "mpt/string/types.hpp"
|
|
|
|
#include <stdexcept>
|
|
|
|
#include "mptString.h"
|
|
|
|
#include "openmpt/base/FlagSet.hpp"
|
|
|
|
|
|
OPENMPT_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
// The following section demands a rationale.
|
|
// 1. mpt::afmt::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.
|
|
// ToAString() 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.
|
|
// When formatting integers, it is recommended to use mpt::afmt::dec or mpt::afmt::hex. Appending a template argument '<n>' 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 FormatValA(int, format) can be
|
|
// used.
|
|
// 3. mpt::format(format)(...) provides simplified and type-safe message and localization string formatting.
|
|
// The only specifier allowed is '{}' enclosing a number 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::afmt mpt::wfmt mpt::ufmt mpt::tfmt mpt::cfmt
|
|
// MPT_AFORMAT("{}") MPT_WFORMAT("{}") MPT_UFORMAT("{}") MPT_TFORMAT("{}") MPT_CFORMAT("{}")
|
|
// 5. All functionality here delegates real work outside of the header file so that <sstream> and <locale> 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 <sstream> and <locale> (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 <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
|
|
#else
|
|
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
|
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
|
|
#else // !MPT_ENABLE_CHARSET_LOCALE
|
|
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
|
|
#endif // MPT_ENABLE_CHARSET_LOCALE
|
|
#endif
|
|
|
|
inline std::string ToAString(const std::string & x) { return x; }
|
|
inline std::string ToAString(const char * const & x) { return x; }
|
|
std::string ToAString(const char &x) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead
|
|
#if MPT_WSTRING_FORMAT
|
|
std::string ToAString(const std::wstring & x) = delete; // Unknown encoding.
|
|
std::string ToAString(const wchar_t * const & x) = delete; // Unknown encoding.
|
|
std::string ToAString(const wchar_t &x ) = delete; // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
|
|
#endif
|
|
#if MPT_USTRING_MODE_UTF8
|
|
std::string ToAString(const mpt::ustring & x) = delete; // Unknown encoding.
|
|
#endif
|
|
#if defined(MPT_WITH_MFC)
|
|
std::string ToAString(const CString & x) = delete; // unknown encoding
|
|
#endif // MPT_WITH_MFC
|
|
std::string ToAString(const bool & x);
|
|
std::string ToAString(const signed char & x);
|
|
std::string ToAString(const unsigned char & x);
|
|
std::string ToAString(const signed short & x);
|
|
std::string ToAString(const unsigned short & x);
|
|
std::string ToAString(const signed int & x);
|
|
std::string ToAString(const unsigned int & x);
|
|
std::string ToAString(const signed long & x);
|
|
std::string ToAString(const unsigned long & x);
|
|
std::string ToAString(const signed long long & x);
|
|
std::string ToAString(const unsigned long long & x);
|
|
std::string ToAString(const float & x);
|
|
std::string ToAString(const double & x);
|
|
std::string ToAString(const long double & x);
|
|
|
|
// fallback to member function ToUString()
|
|
template <typename T> auto ToUString(const T & x) -> decltype(x.ToUString()) { return x.ToUString(); }
|
|
|
|
inline mpt::ustring ToUString(const mpt::ustring & x) { return x; }
|
|
mpt::ustring ToUString(const std::string & x) = delete; // Unknown encoding.
|
|
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.
|
|
mpt::ustring ToUString(const char & x) = delete; // 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::ustring ToUString(const wchar_t & x) = delete; // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
|
|
#endif
|
|
#if defined(MPT_WITH_MFC)
|
|
mpt::ustring ToUString(const CString & x);
|
|
#endif // MPT_WITH_MFC
|
|
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
|
|
std::wstring ToWString(const std::string & x) = delete; // Unknown encoding.
|
|
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.
|
|
std::wstring ToWString(const char & x) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead
|
|
inline std::wstring ToWString(const std::wstring & x) { return x; }
|
|
inline std::wstring ToWString(const wchar_t * const & x) { return x; }
|
|
std::wstring ToWString(const wchar_t & x) = delete; // 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(MPT_WITH_MFC)
|
|
std::wstring ToWString(const CString & x);
|
|
#endif // MPT_WITH_MFC
|
|
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 <typename T> auto ToWString(const T & x) -> decltype(mpt::ToWide(x.ToUString())) { return mpt::ToWide(x.ToUString()); }
|
|
#endif
|
|
|
|
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
|
template <typename T> struct ToLocaleHelper { mpt::lstring operator () (const T & v) { return mpt::ToLocale(ToUString(v)); } };
|
|
template <> struct ToLocaleHelper<mpt::lstring> { mpt::lstring operator () (const mpt::lstring & v) { return v; } };
|
|
#endif // MPT_ENABLE_CHARSET_LOCALE
|
|
|
|
#if defined(MPT_WITH_MFC)
|
|
template <typename T> struct ToCStringHelper { CString operator () (const T & v) { return mpt::ToCString(ToUString(v)); } };
|
|
template <> struct ToCStringHelper<CString> { CString operator () (const CString & v) { return v; } };
|
|
#endif // MPT_WITH_MFC
|
|
|
|
template <typename Tstring> struct ToStringTFunctor {};
|
|
template <> struct ToStringTFunctor<std::string> { template <typename T> inline std::string operator() (const T & x) { return ToAString(x); } };
|
|
template <> struct ToStringTFunctor<mpt::ustring> { template <typename T> inline mpt::ustring operator() (const T & x) { return ToUString(x); } };
|
|
#if MPT_WSTRING_FORMAT && MPT_USTRING_MODE_UTF8
|
|
template <> struct ToStringTFunctor<std::wstring> { template <typename T> inline std::wstring operator() (const T & x) { return ToWString(x); } };
|
|
#endif
|
|
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
|
template <> struct ToStringTFunctor<mpt::lstring> { template <typename T> inline mpt::lstring operator() (const T & x) { return mpt::ToLocaleHelper<T>()(x); } };
|
|
#endif // MPT_ENABLE_CHARSET_LOCALE
|
|
#if defined(MPT_WITH_MFC)
|
|
template <> struct ToStringTFunctor<CString> { template <typename T> inline CString operator() (const T & x) { return mpt::ToCStringHelper<T>()(x); } };
|
|
#endif // MPT_WITH_MFC
|
|
|
|
template<typename Tstring, typename T> inline Tstring ToStringT(const T & x) { return ToStringTFunctor<Tstring>()(x); }
|
|
|
|
|
|
struct ToStringFormatter {
|
|
template <typename Tstring, typename T>
|
|
static inline Tstring format(const T& value) {
|
|
return ToStringTFunctor<Tstring>()(value);
|
|
|
|
}
|
|
};
|
|
|
|
|
|
using FormatSpec = mpt::format_simple_spec;
|
|
|
|
using FormatFlags = mpt::format_simple_flags;
|
|
|
|
using fmt_base = mpt::format_simple_base;
|
|
|
|
|
|
std::string FormatValA(const char & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead
|
|
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
|
std::string FormatValA(const wchar_t & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
|
|
#endif // !MPT_COMPILER_QUIRK_NO_WCHAR
|
|
std::string FormatValA(const bool & x, const FormatSpec & f);
|
|
std::string FormatValA(const signed char & x, const FormatSpec & f);
|
|
std::string FormatValA(const unsigned char & x, const FormatSpec & f);
|
|
std::string FormatValA(const signed short & x, const FormatSpec & f);
|
|
std::string FormatValA(const unsigned short & x, const FormatSpec & f);
|
|
std::string FormatValA(const signed int & x, const FormatSpec & f);
|
|
std::string FormatValA(const unsigned int & x, const FormatSpec & f);
|
|
std::string FormatValA(const signed long & x, const FormatSpec & f);
|
|
std::string FormatValA(const unsigned long & x, const FormatSpec & f);
|
|
std::string FormatValA(const signed long long & x, const FormatSpec & f);
|
|
std::string FormatValA(const unsigned long long & x, const FormatSpec & f);
|
|
std::string FormatValA(const float & x, const FormatSpec & f);
|
|
std::string FormatValA(const double & x, const FormatSpec & f);
|
|
std::string FormatValA(const long double & x, const FormatSpec & f);
|
|
|
|
mpt::ustring FormatValU(const char & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead
|
|
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
|
mpt::ustring FormatValU(const wchar_t & x, const FormatSpec & f) = delete; // 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
|
|
std::wstring FormatValW(const char & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead
|
|
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
|
std::wstring FormatValW(const wchar_t & x, const FormatSpec & f) = delete; // 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 <typename Tstring> struct FormatValTFunctor {};
|
|
template <> struct FormatValTFunctor<std::string> { template <typename T> inline std::string operator() (const T & x, const FormatSpec & f) { return FormatValA(x, f); } };
|
|
template <> struct FormatValTFunctor<mpt::ustring> { template <typename T> 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<std::wstring> { template <typename T> inline std::wstring operator() (const T & x, const FormatSpec & f) { return FormatValW(x, f); } };
|
|
#endif
|
|
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
|
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)); } };
|
|
#endif // MPT_ENABLE_CHARSET_LOCALE
|
|
#if defined(MPT_WITH_MFC)
|
|
#ifdef UNICODE
|
|
template <> struct FormatValTFunctor<CString> { template <typename T> inline CString operator() (const T & x, const FormatSpec & f) { return mpt::ToCString(FormatValW(x, f)); } };
|
|
#else // !UNICODE
|
|
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)); } };
|
|
#endif // UNICODE
|
|
#endif // MPT_WITH_MFC
|
|
|
|
|
|
template <typename Tstring>
|
|
struct fmtT : fmt_base
|
|
{
|
|
|
|
template<typename T>
|
|
static inline Tstring val(const T& x)
|
|
{
|
|
return ToStringTFunctor<Tstring>()(x);
|
|
}
|
|
|
|
template<typename T>
|
|
static inline Tstring fmt(const T& x, const FormatSpec& f)
|
|
{
|
|
return FormatValTFunctor<Tstring>()(x, f);
|
|
}
|
|
|
|
template<typename T>
|
|
static inline Tstring dec(const T& x)
|
|
{
|
|
static_assert(std::numeric_limits<T>::is_integer);
|
|
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseDec().FillOff());
|
|
}
|
|
template<int width, typename T>
|
|
static inline Tstring dec0(const T& x)
|
|
{
|
|
static_assert(std::numeric_limits<T>::is_integer);
|
|
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseDec().FillNul().Width(width));
|
|
}
|
|
|
|
template<typename T>
|
|
static inline Tstring dec(unsigned int g, char s, const T& x)
|
|
{
|
|
static_assert(std::numeric_limits<T>::is_integer);
|
|
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseDec().FillOff().Group(g).GroupSep(s));
|
|
}
|
|
template<int width, typename T>
|
|
static inline Tstring dec0(unsigned int g, char s, const T& x)
|
|
{
|
|
static_assert(std::numeric_limits<T>::is_integer);
|
|
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseDec().FillNul().Width(width).Group(g).GroupSep(s));
|
|
}
|
|
|
|
template<typename T>
|
|
static inline Tstring hex(const T& x)
|
|
{
|
|
static_assert(std::numeric_limits<T>::is_integer);
|
|
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseLow().FillOff());
|
|
}
|
|
template<typename T>
|
|
static inline Tstring HEX(const T& x)
|
|
{
|
|
static_assert(std::numeric_limits<T>::is_integer);
|
|
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseUpp().FillOff());
|
|
}
|
|
template<int width, typename T>
|
|
static inline Tstring hex0(const T& x)
|
|
{
|
|
static_assert(std::numeric_limits<T>::is_integer);
|
|
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseLow().FillNul().Width(width));
|
|
}
|
|
template<int width, typename T>
|
|
static inline Tstring HEX0(const T& x)
|
|
{
|
|
static_assert(std::numeric_limits<T>::is_integer);
|
|
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseUpp().FillNul().Width(width));
|
|
}
|
|
|
|
template<typename T>
|
|
static inline Tstring hex(unsigned int g, char s, const T& x)
|
|
{
|
|
static_assert(std::numeric_limits<T>::is_integer);
|
|
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseLow().FillOff().Group(g).GroupSep(s));
|
|
}
|
|
template<typename T>
|
|
static inline Tstring HEX(unsigned int g, char s, const T& x)
|
|
{
|
|
static_assert(std::numeric_limits<T>::is_integer);
|
|
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseUpp().FillOff().Group(g).GroupSep(s));
|
|
}
|
|
template<int width, typename T>
|
|
static inline Tstring hex0(unsigned int g, char s, const T& x)
|
|
{
|
|
static_assert(std::numeric_limits<T>::is_integer);
|
|
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseLow().FillNul().Width(width).Group(g).GroupSep(s));
|
|
}
|
|
template<int width, typename T>
|
|
static inline Tstring HEX0(unsigned int g, char s, const T& x)
|
|
{
|
|
static_assert(std::numeric_limits<T>::is_integer);
|
|
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseUpp().FillNul().Width(width).Group(g).GroupSep(s));
|
|
}
|
|
|
|
template<typename T>
|
|
static inline Tstring flt(const T& x, int precision = -1)
|
|
{
|
|
static_assert(std::is_floating_point<T>::value);
|
|
return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaNrm().FillOff().Precision(precision));
|
|
}
|
|
template<typename T>
|
|
static inline Tstring fix(const T& x, int precision = -1)
|
|
{
|
|
static_assert(std::is_floating_point<T>::value);
|
|
return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaFix().FillOff().Precision(precision));
|
|
}
|
|
template<typename T>
|
|
static inline Tstring sci(const T& x, int precision = -1)
|
|
{
|
|
static_assert(std::is_floating_point<T>::value);
|
|
return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaSci().FillOff().Precision(precision));
|
|
}
|
|
|
|
template<typename T>
|
|
static inline Tstring ptr(const T& x)
|
|
{
|
|
static_assert(std::is_pointer<T>::value || std::is_same<T, std::uintptr_t>::value || std::is_same<T, std::intptr_t>::value, "");
|
|
return hex0<mpt::pointer_size * 2>(mpt::pointer_cast<const std::uintptr_t>(x));
|
|
}
|
|
template<typename T>
|
|
static inline Tstring PTR(const T& x)
|
|
{
|
|
static_assert(std::is_pointer<T>::value || std::is_same<T, std::uintptr_t>::value || std::is_same<T, std::intptr_t>::value, "");
|
|
return HEX0<mpt::pointer_size * 2>(mpt::pointer_cast<const std::uintptr_t>(x));
|
|
}
|
|
|
|
static inline Tstring pad_left(std::size_t width_, const Tstring &str)
|
|
{
|
|
typedef mpt::string_traits<Tstring> traits;
|
|
typename traits::size_type width = static_cast<typename traits::size_type>(width_);
|
|
return traits::pad(str, width, 0);
|
|
}
|
|
static inline Tstring pad_right(std::size_t width_, const Tstring &str)
|
|
{
|
|
typedef mpt::string_traits<Tstring> traits;
|
|
typename traits::size_type width = static_cast<typename traits::size_type>(width_);
|
|
return traits::pad(str, 0, width);
|
|
}
|
|
static inline Tstring left(std::size_t width_, const Tstring &str)
|
|
{
|
|
typedef mpt::string_traits<Tstring> traits;
|
|
typename traits::size_type width = static_cast<typename traits::size_type>(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<Tstring> traits;
|
|
typename traits::size_type width = static_cast<typename traits::size_type>(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<Tstring> traits;
|
|
typename traits::size_type width = static_cast<typename traits::size_type>(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<std::string> afmt;
|
|
#if MPT_WSTRING_FORMAT
|
|
typedef fmtT<std::wstring> wfmt;
|
|
#endif
|
|
#if MPT_USTRING_MODE_WIDE
|
|
typedef fmtT<std::wstring> ufmt;
|
|
#else
|
|
typedef fmtT<mpt::ustring> ufmt;
|
|
#endif
|
|
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
|
typedef fmtT<mpt::lstring> lfmt;
|
|
#endif // MPT_ENABLE_CHARSET_LOCALE
|
|
#if MPT_OS_WINDOWS
|
|
typedef fmtT<mpt::tstring> tfmt;
|
|
#endif
|
|
#if defined(MPT_WITH_MFC)
|
|
typedef fmtT<CString> cfmt;
|
|
#endif // MPT_WITH_MFC
|
|
|
|
|
|
#define MPT_AFORMAT(f) mpt::format_message<mpt::ToStringFormatter, mpt::parse_format_string_argument_count(f)>(f)
|
|
|
|
#if MPT_WSTRING_FORMAT
|
|
#define MPT_WFORMAT(f) mpt::format_message_typed<mpt::ToStringFormatter, mpt::parse_format_string_argument_count( L ## f ), std::wstring>( L ## f )
|
|
#endif
|
|
|
|
#define MPT_UFORMAT(f) mpt::format_message_typed<mpt::ToStringFormatter, mpt::parse_format_string_argument_count(MPT_ULITERAL(f)), mpt::ustring>(MPT_ULITERAL(f))
|
|
|
|
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
|
#define MPT_LFORMAT(f) mpt::format_message_typed<mpt::ToStringFormatter, mpt::parse_format_string_argument_count(f), mpt::lstring>(f)
|
|
#endif // MPT_ENABLE_CHARSET_LOCALE
|
|
|
|
#if MPT_OS_WINDOWS
|
|
#define MPT_TFORMAT(f) mpt::format_message_typed<mpt::ToStringFormatter, mpt::parse_format_string_argument_count(TEXT(f)), mpt::tstring>(TEXT(f))
|
|
#endif
|
|
|
|
#if defined(MPT_WITH_MFC)
|
|
#define MPT_CFORMAT(f) mpt::format_message_typed<mpt::ToStringFormatter, mpt::parse_format_string_argument_count(TEXT(f)), CString>(TEXT(f))
|
|
#endif // MPT_WITH_MFC
|
|
|
|
|
|
} // namespace mpt
|
|
|
|
|
|
|
|
namespace mpt { namespace String {
|
|
|
|
// Combine a vector of values into a string, separated with the given separator.
|
|
// No escaping is performed.
|
|
template<typename T>
|
|
mpt::ustring Combine(const std::vector<T> &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<typename T>
|
|
std::string Combine(const std::vector<T> &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::afmt::val(vals[i]);
|
|
}
|
|
return str;
|
|
}
|
|
|
|
} } // namespace mpt::String
|
|
|
|
|
|
|
|
template <typename enum_t, typename store_t>
|
|
mpt::ustring ToUString(FlagSet<enum_t, store_t> flagset)
|
|
{
|
|
mpt::ustring str(flagset.size_bits(), UC_('0'));
|
|
|
|
for(std::size_t x = 0; x < flagset.size_bits(); ++x)
|
|
{
|
|
str[flagset.size_bits() - x - 1] = (flagset.value().as_bits() & (static_cast<typename FlagSet<enum_t>::store_type>(1) << x) ? UC_('1') : UC_('0'));
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
|
|
|
|
|
|
OPENMPT_NAMESPACE_END
|