mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 02:37:36 +02:00
Add UTF-8 types
This commit is contained in:
@ -1062,8 +1062,8 @@ const long long format_arg_store<Context, Args...>::TYPES = get_types();
|
|||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
Constructs an `~fmt::format_arg_store` object that contains references to
|
Constructs an `~fmt::format_arg_store` object that contains references to
|
||||||
arguments and can be implicitly converted to `~fmt::format_args`. `Context` can
|
arguments and can be implicitly converted to `~fmt::format_args`. `Context`
|
||||||
be omitted in which case it defaults to `~fmt::context`.
|
can be omitted in which case it defaults to `~fmt::context`.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename Context, typename ...Args>
|
template <typename Context, typename ...Args>
|
||||||
@ -1334,11 +1334,12 @@ inline void print(std::FILE *f, string_view format_str, const Args & ... args) {
|
|||||||
vprint(f, format_str, as);
|
vprint(f, format_str, as);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
Prints formatted data to the file *f* which should be in wide-oriented mode set
|
Prints formatted data to the file *f* which should be in wide-oriented mode
|
||||||
via ``fwide(f, 1)`` or ``_setmode(_fileno(f), _O_U8TEXT)`` on Windows.
|
set via ``fwide(f, 1)`` or ``_setmode(_fileno(f), _O_U8TEXT)`` on Windows.
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline void print(std::FILE *f, wstring_view format_str, const Args & ... args) {
|
inline void print(std::FILE *f, wstring_view format_str,
|
||||||
|
const Args & ... args) {
|
||||||
format_arg_store<wformat_context, Args...> as(args...);
|
format_arg_store<wformat_context, Args...> as(args...);
|
||||||
vprint(f, format_str, as);
|
vprint(f, format_str, as);
|
||||||
}
|
}
|
||||||
|
@ -202,6 +202,16 @@ class locale {
|
|||||||
std::locale get() { return locale_; }
|
std::locale get() { return locale_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
FMT_FUNC size_t internal::count_code_points(u8string_view s) {
|
||||||
|
const char8_t *data = s.data();
|
||||||
|
int num_code_points = 0;
|
||||||
|
for (size_t i = 0, size = s.size(); i != size; ++i) {
|
||||||
|
if ((data[i].value & 0xc0) != 0x80)
|
||||||
|
++num_code_points;
|
||||||
|
}
|
||||||
|
return num_code_points;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
|
FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
|
||||||
std::locale loc = lp ? lp->locale().get() : std::locale();
|
std::locale loc = lp ? lp->locale().get() : std::locale();
|
||||||
|
@ -489,6 +489,37 @@ void basic_buffer<T>::append(const U *begin, const U *end) {
|
|||||||
}
|
}
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
|
// A UTF-8 code unit type.
|
||||||
|
struct char8_t {
|
||||||
|
char value;
|
||||||
|
FMT_CONSTEXPR explicit operator bool() const FMT_NOEXCEPT {
|
||||||
|
return value != 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// A UTF-8 string.
|
||||||
|
class u8string_view : public basic_string_view<char8_t> {
|
||||||
|
private:
|
||||||
|
typedef basic_string_view<char8_t> base;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using basic_string_view::basic_string_view;
|
||||||
|
|
||||||
|
u8string_view(const char *s)
|
||||||
|
: base(reinterpret_cast<const char8_t*>(s)) {}
|
||||||
|
|
||||||
|
u8string_view(const char *s, size_t count) FMT_NOEXCEPT
|
||||||
|
: base(reinterpret_cast<const char8_t*>(s), count) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if FMT_USE_USER_DEFINED_LITERALS
|
||||||
|
inline namespace literals {
|
||||||
|
inline u8string_view operator"" _u(const char *s, std::size_t n) {
|
||||||
|
return u8string_view(s, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// A wrapper around std::locale used to reduce compile times since <locale>
|
// A wrapper around std::locale used to reduce compile times since <locale>
|
||||||
// is very heavy.
|
// is very heavy.
|
||||||
class locale;
|
class locale;
|
||||||
@ -950,6 +981,9 @@ inline unsigned count_digits(uint64_t n) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Counts the number of code points in a UTF-8 string.
|
||||||
|
FMT_API size_t count_code_points(u8string_view s);
|
||||||
|
|
||||||
#if FMT_HAS_CPP_ATTRIBUTE(always_inline)
|
#if FMT_HAS_CPP_ATTRIBUTE(always_inline)
|
||||||
# define FMT_ALWAYS_INLINE __attribute__((always_inline))
|
# define FMT_ALWAYS_INLINE __attribute__((always_inline))
|
||||||
#else
|
#else
|
||||||
@ -3514,7 +3548,8 @@ template <typename... Args, std::size_t SIZE = inline_buffer_size>
|
|||||||
inline wformat_context::iterator format_to(
|
inline wformat_context::iterator format_to(
|
||||||
basic_memory_buffer<wchar_t, SIZE> &buf, wstring_view format_str,
|
basic_memory_buffer<wchar_t, SIZE> &buf, wstring_view format_str,
|
||||||
const Args & ... args) {
|
const Args & ... args) {
|
||||||
return vformat_to(buf, format_str, make_format_args<wformat_context>(args...));
|
return vformat_to(buf, format_str,
|
||||||
|
make_format_args<wformat_context>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename Char = char>
|
template <typename OutputIt, typename Char = char>
|
||||||
@ -3573,7 +3608,8 @@ inline typename std::enable_if<
|
|||||||
is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type
|
is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type
|
||||||
format_to(std::back_insert_iterator<Container> out,
|
format_to(std::back_insert_iterator<Container> out,
|
||||||
wstring_view format_str, const Args & ... args) {
|
wstring_view format_str, const Args & ... args) {
|
||||||
return vformat_to(out, format_str, make_format_args<wformat_context>(args...));
|
return vformat_to(out, format_str,
|
||||||
|
make_format_args<wformat_context>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt>
|
template <typename OutputIt>
|
||||||
@ -3847,10 +3883,12 @@ inline void print(rgb fd, string_view format_str, const Args & ... args) {
|
|||||||
Formats a string and prints it to stdout using ANSI escape sequences to
|
Formats a string and prints it to stdout using ANSI escape sequences to
|
||||||
specify foreground color 'fd' and background color 'bg'.
|
specify foreground color 'fd' and background color 'bg'.
|
||||||
Example:
|
Example:
|
||||||
fmt::print(fmt::color::red, fmt::color::black, "Elapsed time: {0:.2f} seconds", 1.23);
|
fmt::print(fmt::color::red, fmt::color::black,
|
||||||
|
"Elapsed time: {0:.2f} seconds", 1.23);
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
inline void print(rgb fd, rgb bg, string_view format_str, const Args & ... args) {
|
inline void print(rgb fd, rgb bg, string_view format_str,
|
||||||
|
const Args & ... args) {
|
||||||
vprint_rgb(fd, bg, format_str, make_format_args(args...));
|
vprint_rgb(fd, bg, format_str, make_format_args(args...));
|
||||||
}
|
}
|
||||||
#endif // FMT_EXTENDED_COLORS
|
#endif // FMT_EXTENDED_COLORS
|
||||||
|
@ -118,9 +118,13 @@ TEST(FormatTest, FormatErrorCode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(FormatTest, CountCodePoints) {
|
||||||
|
EXPECT_EQ(4, fmt::internal::count_code_points(fmt::u8string_view("ёжик")));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ColorsTest, Colors) {
|
TEST(ColorsTest, Colors) {
|
||||||
EXPECT_WRITE(stdout, fmt::print(fmt::rgb(255,20,30), "rgb(255,20,30)"),
|
EXPECT_WRITE(stdout, fmt::print(fmt::rgb(255,20,30), "rgb(255,20,30)"),
|
||||||
"\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m");
|
"\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m");
|
||||||
EXPECT_WRITE(stdout, fmt::print(fmt::color::blue,"blue"),
|
EXPECT_WRITE(stdout, fmt::print(fmt::color::blue, "blue"),
|
||||||
"\x1b[38;2;000;000;255mblue\x1b[0m");
|
"\x1b[38;2;000;000;255mblue\x1b[0m");
|
||||||
}
|
}
|
||||||
|
@ -1932,3 +1932,30 @@ TEST(FormatTest, FormatStringErrors) {
|
|||||||
}
|
}
|
||||||
#endif // FMT_USE_CONSTEXPR
|
#endif // FMT_USE_CONSTEXPR
|
||||||
|
|
||||||
|
TEST(FormatTest, ConstructU8StringViewFromCString) {
|
||||||
|
fmt::u8string_view s("ab");
|
||||||
|
EXPECT_EQ(s.size(), 2u);
|
||||||
|
const fmt::char8_t *data = s.data();
|
||||||
|
EXPECT_EQ(data[0].value, 'a');
|
||||||
|
EXPECT_EQ(data[1].value, 'b');
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatTest, ConstructU8StringViewFromDataAndSize) {
|
||||||
|
fmt::u8string_view s("foobar", 3);
|
||||||
|
EXPECT_EQ(s.size(), 3u);
|
||||||
|
const fmt::char8_t *data = s.data();
|
||||||
|
EXPECT_EQ(data[0].value, 'f');
|
||||||
|
EXPECT_EQ(data[1].value, 'o');
|
||||||
|
EXPECT_EQ(data[2].value, 'o');
|
||||||
|
}
|
||||||
|
|
||||||
|
#if FMT_USE_USER_DEFINED_LITERALS
|
||||||
|
TEST(FormatTest, U8StringViewLiteral) {
|
||||||
|
using namespace fmt::literals;
|
||||||
|
fmt::u8string_view s = "ab"_u;
|
||||||
|
EXPECT_EQ(s.size(), 2u);
|
||||||
|
const fmt::char8_t *data = s.data();
|
||||||
|
EXPECT_EQ(data[0].value, 'a');
|
||||||
|
EXPECT_EQ(data[1].value, 'b');
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -868,7 +868,8 @@ TEST(UtilTest, IsEnumConvertibleToInt) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
TEST(UtilTest, ParseNonnegativeInt) {
|
TEST(UtilTest, ParseNonnegativeInt) {
|
||||||
if (std::numeric_limits<int>::max() != static_cast<int>(static_cast<unsigned>(1) << 31)) {
|
if (std::numeric_limits<int>::max() !=
|
||||||
|
static_cast<int>(static_cast<unsigned>(1) << 31)) {
|
||||||
fmt::print("Skipping parse_nonnegative_int test\n");
|
fmt::print("Skipping parse_nonnegative_int test\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user