File: mptStringFormat.h

package info (click to toggle)
libopenmpt 0.8.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 9,844 kB
  • sloc: cpp: 129,366; sh: 4,695; ansic: 1,107; makefile: 712
file content (173 lines) | stat: -rw-r--r-- 7,034 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/*
 * 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/detect.hpp"
#include "mpt/endian/integer.hpp"
#include "mpt/format/default_formatter.hpp"
#include "mpt/format/message.hpp"
#include "mpt/format/message_macros.hpp"
#include "mpt/format/simple.hpp"
#include "mpt/format/simple_spec.hpp"
#include "mpt/string/types.hpp"
#include "mpt/string_transcode/transcode.hpp"

#include "openmpt/base/FlagSet.hpp"

#include "mptString.h"

#include <cstddef>



// 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 {
inline namespace MPT_INLINE_NS {
template <typename Tstring, typename Tint, mpt::endian endian>
inline auto format_value_default(const mpt::packed<Tint, endian> & x) -> decltype(mpt::default_formatter::format<Tstring, Tint>(x)) {
	return mpt::default_formatter::format<Tstring, Tint>(x);
}
} // namespace MPT_INLINE_NS
} // namespace mpt


OPENMPT_NAMESPACE_BEGIN


template <typename Tstring, typename T>
inline auto format_value_default(const T & x) -> decltype(mpt::transcode<Tstring>(x.ToUString())) {
	return mpt::transcode<Tstring>(x.ToUString());
}


template <typename Tstring, typename T>
inline auto format_value_default(const T & x) -> decltype(mpt::transcode<Tstring>(ToUString(x))) {
	return mpt::transcode<Tstring>(ToUString(x));
}


namespace mpt
{


template <typename Tstring, typename T>
inline auto format_value_default(const T & x) -> decltype(mpt::transcode<Tstring>(x.ToUString())) {
	return mpt::transcode<Tstring>(x.ToUString());
}


template <typename Tstring, typename T>
inline auto format_value_default(const T & x) -> decltype(mpt::transcode<Tstring>(ToUString(x))) {
	return mpt::transcode<Tstring>(ToUString(x));
}


template <typename Tstring>
using fmtT = mpt::format<Tstring>;

using afmt = fmtT<std::string>;
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
using wfmt = fmtT<std::wstring>;
#endif
using ufmt = fmtT<mpt::ustring>;
#if defined(MPT_ENABLE_CHARSET_LOCALE)
using lfmt = fmtT<mpt::lstring>;
#endif // MPT_ENABLE_CHARSET_LOCALE
#if MPT_OS_WINDOWS
using tfmt = fmtT<mpt::tstring>;
#endif
#if defined(MPT_WITH_MFC)
using cfmt = fmtT<CString>;
#endif // MPT_WITH_MFC


#define MPT_AFORMAT(f) MPT_AFORMAT_MESSAGE(f)

#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
#define MPT_WFORMAT(f) MPT_WFORMAT_MESSAGE(f)
#endif

#define MPT_UFORMAT(f) MPT_UFORMAT_MESSAGE(f)

#if defined(MPT_ENABLE_CHARSET_LOCALE)
#define MPT_LFORMAT(f) MPT_LFORMAT_MESSAGE(f)
#endif // MPT_ENABLE_CHARSET_LOCALE

#if MPT_OS_WINDOWS
#define MPT_TFORMAT(f) MPT_TFORMAT_MESSAGE(f)
#endif // MPT_OS_WINDOWS

#if defined(MPT_WITH_MFC)
#define MPT_CFORMAT(f) MPT_CFORMAT_MESSAGE(f)
#endif // MPT_WITH_MFC


} // namespace mpt



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