Skip to main content

expression-formatter.cpp File

C++ source file with non-template implementations for the µTest++ expression formatter. More...

Included Headers​

Namespaces Index​

namespacemicro_os_plus

The primary namespace for the µOS++ framework. More...

namespacemicro_test_plus

Primary namespace for the µTest++ testing framework. More...

namespacedetail

Internal implementation details for the µTest++ framework. More...

namespaceanonymous{expression-formatter.cpp}

Local helpers of the expression formatter. More...

Functions Index​

voidappend_control_escape (std::string &text, char c)

Appends the escape sequence of a control character. More...

voidappend_hex (std::string &buffer, char32_t code, std::string_view escape, std::size_t count)

Appends an escape and a fixed number of hexadecimal digits. More...

voidappend_plain (std::string &buffer, std::string_view sv)

Appends a text in the plain mode, with the control characters escaped. More...

voidappend_quoted (std::string &buffer, std::string_view sv)

Appends a string, as a quoted literal. More...

voidappend_utf8 (std::string &text, char32_t code)

Appends a code point to a text, as UTF-8. More...

template <class Char_T>
voidappend_wide_text (std::string &buffer, std::basic_string_view< Char_T > sv)

Appends the text of a string of a wide character type, converted to UTF-8, as the char text is appended. More...

template <class Char_T>
auto bounded_view (const Char_T *s, std::size_t capacity) noexcept -> std::basic_string_view< Char_T >

Returns the text of a C string held in a buffer of a known capacity. More...

constexpr boolis_escaped_in_plain (char c) noexcept

Tells whether a character is escaped in the plain mode. More...

template <class Char_T>
std::stringutf16_to_utf8 (std::basic_string_view< Char_T > sv)

Converts a UTF-16 text to UTF-8. More...

template <class Char_T>
std::stringutf32_to_utf8 (std::basic_string_view< Char_T > sv)

Converts a UTF-32 text to UTF-8. More...

Description​

C++ source file with non-template implementations for the µTest++ expression formatter.

This source file contains the non-template operator<< overloads of expression_formatter for all standard arithmetic, character, string, boolean, and null-pointer types, std::nullopt, and the named_bool operand. Each overload appends the formatted value — together with an appropriate type suffix where applicable — to the internal string buffer. It also contains the private helpers that write the decimal point, the suffixes, and the characters, and the functions that assign the buffer to the checks.

All definitions reside within the micro_os_plus::micro_test_plus::detail namespace.

This file must be included when building the µTest++ library.

Functions​

append_control_escape()​

void micro_os_plus::micro_test_plus::detail::append_control_escape (std::string & text, char c)

Appends the escape sequence of a control character.

Writes the usual escape of the character (\\0, \\a, \\b, \\t, \\n, \\v, \\f, or \\r), or \\xHH for the other ones. Used for the characters of the messages and of the names that would otherwise reach the console and the output files unchanged. Defined in src/expression-formatter.cpp.

Parameters
text

The text to append to.

c

The control character.

The usual escapes for the characters that have one; the other ones, including DEL, as \\xHH.

Definition at line 401 of file expression-formatter.cpp.

401 append_control_escape (std::string& text, char c)
402 {
403 switch (c)
404 {
405 case '\0':
406 text.append ("\\0");
407 break;
408 case '\a':
409 text.append ("\\a");
410 break;
411 case '\b':
412 text.append ("\\b");
413 break;
414 case '\t':
415 text.append ("\\t");
416 break;
417 case '\n':
418 text.append ("\\n");
419 break;
420 case '\v':
421 text.append ("\\v");
422 break;
423 case '\f':
424 text.append ("\\f");
425 break;
426 case '\r':
427 text.append ("\\r");
428 break;
429 default:
430 append_hex (text, static_cast<unsigned char> (c), "\\x", 2);
431 break;
432 }
433 }

Reference micro_os_plus::micro_test_plus::detail::append_control_escape.

Referenced by micro_os_plus::micro_test_plus::detail::append_control_escape, micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_plain, micro_os_plus::micro_test_plus::detail::escape_control_characters and micro_os_plus::micro_test_plus::detail::expression_formatter::operator<<.

append_hex()​

void micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_hex (std::string & buffer, char32_t code, std::string_view escape, std::size_t count)

Appends an escape and a fixed number of hexadecimal digits.

Used by expression_formatter::append_character(); the digits are lowercase, the most significant first, and the leading zeros are kept, so that the number of digits shows the size of the type.

Parameters
buffer

The text to which the escape is appended.

code

The value to write.

escape

The escape before the digits ("\\x", "\\u", or "\\U").

count

The number of digits.

Returns

Nothing.

Definition at line 99 of file expression-formatter.cpp.

99 append_hex (std::string& buffer, char32_t code, std::string_view escape,
100 std::size_t count)
101 {
102 constexpr std::string_view digits{ "0123456789abcdef" };
103 buffer.append (escape);
104 for (std::size_t i = count; i > 0; --i)
105 {
106 // The promoted type of `code` is `std::size_t` on some
107 // platforms, so a cast would be reported as useless.
108 const auto nibble = (code >> ((i - 1) * 4)) & 0x0Fu;
109 buffer.push_back (digits[nibble]);
110 }
111 }

Reference micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_hex.

Referenced by micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_hex and micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_quoted.

append_plain()​

void micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_plain (std::string & buffer, std::string_view sv)

Appends a text in the plain mode, with the control characters escaped.

Parameters
buffer

The buffer to append to.

sv

The text.

The characters selected by is_escaped_in_plain() are written by append_control_escape(); all the others, including the tab, the line feed, and the bytes of the UTF-8 sequences, unchanged.

Definition at line 322 of file expression-formatter.cpp.

322 append_plain (std::string& buffer, std::string_view sv)
323 {
324 for (const char c : sv)
325 {
326 if (is_escaped_in_plain (c))
327 {
328 append_control_escape (buffer, c);
329 }
330 else
331 {
332 buffer.push_back (c);
333 }
334 }
335 }

References micro_os_plus::micro_test_plus::detail::append_control_escape, micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_plain and micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::is_escaped_in_plain.

Referenced by micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_plain.

append_quoted()​

void micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_quoted (std::string & buffer, std::string_view sv)

Appends a string, as a quoted literal.

Used by the string operands, so that the empty strings and the leading or trailing spaces are visible, and the control characters do not reach the console. The escapes are those of the character literals, with the double quote escaped instead of the single quote. The bytes above 0x7F are written unchanged, so that the UTF-8 text remains readable.

Parameters
buffer

The text to which the literal is appended.

sv

The string to write; it may contain '\\0'.

Returns

Nothing.

Definition at line 130 of file expression-formatter.cpp.

130 append_quoted (std::string& buffer, std::string_view sv)
131 {
132 buffer.push_back ('"');
133 for (const char c : sv)
134 {
135 switch (c)
136 {
137 case '\0':
138 buffer.append ("\\0");
139 break;
140 case '\a':
141 buffer.append ("\\a");
142 break;
143 case '\b':
144 buffer.append ("\\b");
145 break;
146 case '\t':
147 buffer.append ("\\t");
148 break;
149 case '\n':
150 buffer.append ("\\n");
151 break;
152 case '\v':
153 buffer.append ("\\v");
154 break;
155 case '\f':
156 buffer.append ("\\f");
157 break;
158 case '\r':
159 buffer.append ("\\r");
160 break;
161 case '"':
162 buffer.append ("\\\"");
163 break;
164 case '\\':
165 buffer.append ("\\\\");
166 break;
167 default:
168 if (static_cast<unsigned char> (c) < 0x20 || c == 0x7F)
169 {
170 append_hex (buffer, static_cast<unsigned char> (c), "\\x",
171 2);
172 }
173 else
174 {
175 buffer.push_back (c);
176 }
177 break;
178 }
179 }
180 buffer.push_back ('"');
181 }

References micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_hex and micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_quoted.

Referenced by micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_quoted.

append_utf8()​

void micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_utf8 (std::string & text, char32_t code)

Appends a code point to a text, as UTF-8.

A value that is not a Unicode scalar value (a surrogate, or a value above U+10FFFF) is written as the replacement character U+FFFD.

Parameters
text

The text to append to.

code

The code point.

Definition at line 194 of file expression-formatter.cpp.

194 append_utf8 (std::string& text, char32_t code)
195 {
196 if ((code >= 0xD800 && code <= 0xDFFF) || code > 0x10FFFF)
197 {
198 code = 0xFFFD;
199 }
200
201 if (code < 0x80)
202 {
203 text.push_back (static_cast<char> (code));
204 }
205 else if (code < 0x800)
206 {
207 text.push_back (static_cast<char> (0xC0 | (code >> 6)));
208 text.push_back (static_cast<char> (0x80 | (code & 0x3F)));
209 }
210 else if (code < 0x10000)
211 {
212 text.push_back (static_cast<char> (0xE0 | (code >> 12)));
213 text.push_back (static_cast<char> (0x80 | ((code >> 6) & 0x3F)));
214 text.push_back (static_cast<char> (0x80 | (code & 0x3F)));
215 }
216 else
217 {
218 text.push_back (static_cast<char> (0xF0 | (code >> 18)));
219 text.push_back (static_cast<char> (0x80 | ((code >> 12) & 0x3F)));
220 text.push_back (static_cast<char> (0x80 | ((code >> 6) & 0x3F)));
221 text.push_back (static_cast<char> (0x80 | (code & 0x3F)));
222 }
223 }

Reference micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_utf8.

Referenced by micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_utf8, micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::utf16_to_utf8 and micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::utf32_to_utf8.

append_wide_text()​

template <class Char_T>
void micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_wide_text (std::string & buffer, std::basic_string_view< Char_T > sv)

Appends the text of a string of a wide character type, converted to UTF-8, as the char text is appended.

The text is written by a formatter in the plain mode, so without quotes, with the control characters other than the tab and the line feed, and DEL, escaped, whatever the mode of the caller.

Template Parameters
Char_T

The character type.

Parameters
[inout] buffer

The buffer to append to.

sv

The text.

Returns

Nothing.

Definition at line 385 of file expression-formatter.cpp.

385 append_wide_text (std::string& buffer, std::basic_string_view<Char_T> sv)
386 {
387 std::string text;
388 plain_text::append (text, sv);
389 buffer.append (text);
390 }

References micro_os_plus::micro_test_plus::detail::plain_text::append and micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_wide_text.

Referenced by micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_wide_text.

bounded_view()​

template <class Char_T>
std::basic_string_view< Char_T > micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::bounded_view (const Char_T * s, std::size_t capacity)
noexcept

Returns the text of a C string held in a buffer of a known capacity.

With npos, the length is computed by the constructor of the view, which reads up to the terminator; otherwise only the capacity characters are searched for the terminator, so that an array without one is not read beyond its end.

Template Parameters
Char_T

The character type.

Parameters
s

The text; it must not be null.

capacity

The number of characters that may be read, or npos if the text is null-terminated.

Returns

A view of the characters before the first null character, or of the capacity characters if there is none.

Definition at line 356 of file expression-formatter.cpp.

356 bounded_view (const Char_T* s, std::size_t capacity) noexcept
357 {
358 if (capacity == std::basic_string_view<Char_T>::npos)
359 {
360 return std::basic_string_view<Char_T>{ s };
361 }
362
363 const std::basic_string_view<Char_T> buffer{ s, capacity };
364 return buffer.substr (0, buffer.find (Char_T{}));
365 }

Reference micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::bounded_view.

Referenced by micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::bounded_view.

is_escaped_in_plain()​

bool micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::is_escaped_in_plain (char c)
constexpr noexcept

Tells whether a character is escaped in the plain mode.

The control characters other than the tab and the line feed, and the DEL character, which can change the state of a terminal, and truncate a text.

Parameters
c

The character.

Return Values
true

The character is escaped.

false

The character is written unchanged.

Definition at line 303 of file expression-formatter.cpp.

303 is_escaped_in_plain (char c) noexcept
304 {
305 const auto unit = static_cast<unsigned char> (c);
306 return (unit < 0x20 && c != '\t' && c != '\n') || unit == 0x7F;
307 }

Reference micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::is_escaped_in_plain.

Referenced by micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_plain and micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::is_escaped_in_plain.

utf16_to_utf8()​

template <class Char_T>
std::string micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::utf16_to_utf8 (std::basic_string_view< Char_T > sv)

Converts a UTF-16 text to UTF-8.

The surrogate pairs are combined; an unpaired surrogate is written as the replacement character.

Template Parameters
Char_T

A character type of at least 16 bits, holding UTF-16 code units.

Parameters
sv

The text to convert.

Returns

The UTF-8 text.

Definition at line 240 of file expression-formatter.cpp.

240 utf16_to_utf8 (std::basic_string_view<Char_T> sv)
241 {
242 std::string text;
243 text.reserve (sv.size ());
244 for (std::size_t i = 0; i < sv.size (); ++i)
245 {
246 const auto unit = static_cast<char32_t> (sv[i]) & 0xFFFFu;
247 if (unit >= 0xD800 && unit <= 0xDBFF && i + 1 < sv.size ())
248 {
249 const auto next = static_cast<char32_t> (sv[i + 1]) & 0xFFFFu;
250 if (next >= 0xDC00 && next <= 0xDFFF)
251 {
252 append_utf8 (text, 0x10000 + ((unit - 0xD800) << 10)
253 + (next - 0xDC00));
254 ++i;
255 continue;
256 }
257 }
258 append_utf8 (text, unit);
259 }
260 return text;
261 }

References micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_utf8 and micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::utf16_to_utf8.

Referenced by micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::utf16_to_utf8.

utf32_to_utf8()​

template <class Char_T>
std::string micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::utf32_to_utf8 (std::basic_string_view< Char_T > sv)

Converts a UTF-32 text to UTF-8.

Template Parameters
Char_T

A character type of at least 32 bits, holding UTF-32 code units.

Parameters
sv

The text to convert.

Returns

The UTF-8 text.

Unlike UTF-16, UTF-32 needs no decoding: each code unit is encoded by append_utf8(), which writes the values that are not Unicode scalar values as U+FFFD.

Definition at line 279 of file expression-formatter.cpp.

279 utf32_to_utf8 (std::basic_string_view<Char_T> sv)
280 {
281 std::string text;
282 text.reserve (sv.size ());
283 for (const Char_T unit : sv)
284 {
285 append_utf8 (text, static_cast<char32_t> (unit));
286 }
287 return text;
288 }

References micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::append_utf8 and micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::utf32_to_utf8.

Referenced by micro_os_plus::micro_test_plus::detail::anonymous{expression-formatter.cpp}::utf32_to_utf8.

File Listing​

The file content with the documentation metadata removed is:

1/*
2 * This file is part of the µOS++ project (https://micro-os-plus.github.io/).
3 * Copyright (c) 2021-2026 Liviu Ionescu. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose is hereby granted, under the terms of the MIT license.
7 *
8 * If a copy of the license was not distributed with this file, it can be
9 * obtained from https://opensource.org/licenses/mit.
10 *
11 * Major parts of the code are inspired from v1.1.8 of the Boost UT project,
12 * released under the terms of the Boost Version 1.0 Software License,
13 * which can be obtained from https://www.boost.org/LICENSE_1_0.txt.
14 */
15
16// ----------------------------------------------------------------------------
17
38
39// ----------------------------------------------------------------------------
40
43
44#include <cmath>
45
46// ----------------------------------------------------------------------------
47
48#if defined(__GNUC__)
49#pragma GCC diagnostic ignored "-Waggregate-return"
50#if defined(__clang__)
51#pragma clang diagnostic ignored "-Wc++98-compat"
52#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
53#pragma clang diagnostic ignored "-Wexit-time-destructors"
54#endif // defined(__clang__)
55#endif // defined(__GNUC__)
56
57// ============================================================================
58
59#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_ENABLED)
60
61// ----------------------------------------------------------------------------
62
64{
65 // --------------------------------------------------------------------------
66
80 namespace
81 {
98 void
99 append_hex (std::string& buffer, char32_t code, std::string_view escape,
100 std::size_t count)
101 {
102 constexpr std::string_view digits{ "0123456789abcdef" };
103 buffer.append (escape);
104 for (std::size_t i = count; i > 0; --i)
105 {
106 // The promoted type of `code` is `std::size_t` on some
107 // platforms, so a cast would be reported as useless.
108 const auto nibble = (code >> ((i - 1) * 4)) & 0x0Fu;
109 buffer.push_back (digits[nibble]);
110 }
111 }
112
129 void
130 append_quoted (std::string& buffer, std::string_view sv)
131 {
132 buffer.push_back ('"');
133 for (const char c : sv)
134 {
135 switch (c)
136 {
137 case '\0':
138 buffer.append ("\\0");
139 break;
140 case '\a':
141 buffer.append ("\\a");
142 break;
143 case '\b':
144 buffer.append ("\\b");
145 break;
146 case '\t':
147 buffer.append ("\\t");
148 break;
149 case '\n':
150 buffer.append ("\\n");
151 break;
152 case '\v':
153 buffer.append ("\\v");
154 break;
155 case '\f':
156 buffer.append ("\\f");
157 break;
158 case '\r':
159 buffer.append ("\\r");
160 break;
161 case '"':
162 buffer.append ("\\\"");
163 break;
164 case '\\':
165 buffer.append ("\\\\");
166 break;
167 default:
168 if (static_cast<unsigned char> (c) < 0x20 || c == 0x7F)
169 {
170 append_hex (buffer, static_cast<unsigned char> (c), "\\x",
171 2);
172 }
173 else
174 {
175 buffer.push_back (c);
176 }
177 break;
178 }
179 }
180 buffer.push_back ('"');
181 }
182
193 void
194 append_utf8 (std::string& text, char32_t code)
195 {
196 if ((code >= 0xD800 && code <= 0xDFFF) || code > 0x10FFFF)
197 {
198 code = 0xFFFD;
199 }
200
201 if (code < 0x80)
202 {
203 text.push_back (static_cast<char> (code));
204 }
205 else if (code < 0x800)
206 {
207 text.push_back (static_cast<char> (0xC0 | (code >> 6)));
208 text.push_back (static_cast<char> (0x80 | (code & 0x3F)));
209 }
210 else if (code < 0x10000)
211 {
212 text.push_back (static_cast<char> (0xE0 | (code >> 12)));
213 text.push_back (static_cast<char> (0x80 | ((code >> 6) & 0x3F)));
214 text.push_back (static_cast<char> (0x80 | (code & 0x3F)));
215 }
216 else
217 {
218 text.push_back (static_cast<char> (0xF0 | (code >> 18)));
219 text.push_back (static_cast<char> (0x80 | ((code >> 12) & 0x3F)));
220 text.push_back (static_cast<char> (0x80 | ((code >> 6) & 0x3F)));
221 text.push_back (static_cast<char> (0x80 | (code & 0x3F)));
222 }
223 }
224
238 template <class Char_T>
239 std::string
240 utf16_to_utf8 (std::basic_string_view<Char_T> sv)
241 {
242 std::string text;
243 text.reserve (sv.size ());
244 for (std::size_t i = 0; i < sv.size (); ++i)
245 {
246 const auto unit = static_cast<char32_t> (sv[i]) & 0xFFFFu;
247 if (unit >= 0xD800 && unit <= 0xDBFF && i + 1 < sv.size ())
248 {
249 const auto next = static_cast<char32_t> (sv[i + 1]) & 0xFFFFu;
250 if (next >= 0xDC00 && next <= 0xDFFF)
251 {
252 append_utf8 (text, 0x10000 + ((unit - 0xD800) << 10)
253 + (next - 0xDC00));
254 ++i;
255 continue;
256 }
257 }
258 append_utf8 (text, unit);
259 }
260 return text;
261 }
262
277 template <class Char_T>
278 std::string
279 utf32_to_utf8 (std::basic_string_view<Char_T> sv)
280 {
281 std::string text;
282 text.reserve (sv.size ());
283 for (const Char_T unit : sv)
284 {
285 append_utf8 (text, static_cast<char32_t> (unit));
286 }
287 return text;
288 }
289
302 constexpr bool
303 is_escaped_in_plain (char c) noexcept
304 {
305 const auto unit = static_cast<unsigned char> (c);
306 return (unit < 0x20 && c != '\t' && c != '\n') || unit == 0x7F;
307 }
308
321 void
322 append_plain (std::string& buffer, std::string_view sv)
323 {
324 for (const char c : sv)
325 {
326 if (is_escaped_in_plain (c))
327 {
328 append_control_escape (buffer, c);
329 }
330 else
331 {
332 buffer.push_back (c);
333 }
334 }
335 }
336
354 template <class Char_T>
355 std::basic_string_view<Char_T>
356 bounded_view (const Char_T* s, std::size_t capacity) noexcept
357 {
358 if (capacity == std::basic_string_view<Char_T>::npos)
359 {
360 return std::basic_string_view<Char_T>{ s };
361 }
362
363 const std::basic_string_view<Char_T> buffer{ s, capacity };
364 return buffer.substr (0, buffer.find (Char_T{}));
365 }
366
383 template <class Char_T>
384 void
385 append_wide_text (std::string& buffer, std::basic_string_view<Char_T> sv)
386 {
387 std::string text;
388 plain_text::append (text, sv);
389 buffer.append (text);
390 }
391 } // namespace
392
393 // --------------------------------------------------------------------------
394
400 void
401 append_control_escape (std::string& text, char c)
402 {
403 switch (c)
404 {
405 case '\0':
406 text.append ("\\0");
407 break;
408 case '\a':
409 text.append ("\\a");
410 break;
411 case '\b':
412 text.append ("\\b");
413 break;
414 case '\t':
415 text.append ("\\t");
416 break;
417 case '\n':
418 text.append ("\\n");
419 break;
420 case '\v':
421 text.append ("\\v");
422 break;
423 case '\f':
424 text.append ("\\f");
425 break;
426 case '\r':
427 text.append ("\\r");
428 break;
429 default:
430 append_hex (text, static_cast<unsigned char> (c), "\\x", 2);
431 break;
432 }
433 }
434
435 // --------------------------------------------------------------------------
436
448 expression_formatter::operator<<(std::string_view sv)
449 {
450 if (plain_)
451 {
452 append_plain (buffer_, sv);
453 }
454 else
455 {
456 append_quoted (buffer_, sv);
457 }
458 return *this;
459 }
460
467 expression_formatter::operator<<(std::wstring_view sv)
468 {
469 if constexpr (sizeof (wchar_t) == 2)
470 {
471 return *this << std::string_view{ utf16_to_utf8 (sv) };
472 }
473 else
474 {
475 return *this << std::string_view{ utf32_to_utf8 (sv) };
476 }
477 }
478
479#if defined(__cpp_lib_char8_t)
486 expression_formatter::operator<<(std::u8string_view sv)
487 {
488 return *this << std::string_view{
489 reinterpret_cast<const char*> (sv.data ()), sv.size ()
490 };
491 }
492#endif // defined(__cpp_lib_char8_t)
493
499 expression_formatter::operator<<(std::u16string_view sv)
500 {
501 return *this << std::string_view{ utf16_to_utf8 (sv) };
502 }
503
509 expression_formatter::operator<<(std::u32string_view sv)
510 {
511 return *this << std::string_view{ utf32_to_utf8 (sv) };
512 }
513
530 {
531 if (plain_)
532 {
533 if (is_escaped_in_plain (c))
534 {
536 }
537 else
538 {
539 buffer_.push_back (c);
540 }
541 return *this;
542 }
543
544 append_character ("", static_cast<unsigned char> (c), sizeof (c));
545 return *this;
546 }
547
548#if defined(__cpp_char8_t)
556 {
557 append_character ("u8", static_cast<char32_t> (c), sizeof (c));
558 return *this;
559 }
560#endif // defined(__cpp_char8_t)
561
569 {
570 append_character ("u", static_cast<char32_t> (c), sizeof (c));
571 return *this;
572 }
573
581 {
582 append_character ("U", c, sizeof (c));
583 return *this;
584 }
585
595 {
596 append_character ("L", static_cast<std::make_unsigned_t<wchar_t>> (c),
597 sizeof (c));
598 return *this;
599 }
600
611 void
612 expression_formatter::append_c_string (const char* s, std::size_t capacity)
613 {
614 if (s == nullptr)
615 {
616 buffer_.append ("nullptr");
617 return;
618 }
619
620 append_plain (buffer_, bounded_view (s, capacity));
621 }
622
629 void
631 std::size_t capacity)
632 {
633 if (s == nullptr)
634 {
635 buffer_.append ("nullptr");
636 return;
637 }
638 append_wide_text (buffer_, bounded_view (s, capacity));
639 }
640
641#if defined(__cpp_lib_char8_t)
646 void
648 std::size_t capacity)
649 {
650 if (s == nullptr)
651 {
652 buffer_.append ("nullptr");
653 return;
654 }
655 append_wide_text (buffer_, bounded_view (s, capacity));
656 }
657#endif // defined(__cpp_lib_char8_t)
658
663 void
665 std::size_t capacity)
666 {
667 if (s == nullptr)
668 {
669 buffer_.append ("nullptr");
670 return;
671 }
672 append_wide_text (buffer_, bounded_view (s, capacity));
673 }
674
679 void
681 std::size_t capacity)
682 {
683 if (s == nullptr)
684 {
685 buffer_.append ("nullptr");
686 return;
687 }
688 append_wide_text (buffer_, bounded_view (s, capacity));
689 }
690
691#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
699 {
700 buffer_.append (b.name ());
701 return *this;
702 }
703#endif // defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
704
712 {
713 buffer_.append (v ? "true" : "false");
714 return *this;
715 }
716
723 {
724 buffer_.append ("nullptr");
725 return *this;
726 }
727
735 {
736 buffer_.append ("nullopt");
737 return *this;
738 }
739
749 {
750 const auto start = buffer_.size ();
752 prepend_cast (start, "(signed char)");
753 return *this;
754 }
755
764 {
765 const auto start = buffer_.size ();
767 prepend_cast (start, "(unsigned char)");
768 return *this;
769 }
770
780 {
781 const auto start = buffer_.size ();
783 prepend_cast (start, "(short)");
784 return *this;
785 }
786
795 expression_formatter::operator<<(unsigned short v)
796 {
797 const auto start = buffer_.size ();
799 prepend_cast (start, "(unsigned short)");
800 return *this;
801 }
802
810 {
812 return *this;
813 }
814
822 {
824 append_suffix ("u");
825 return *this;
826 }
827
835 {
837 append_suffix ("l");
838 return *this;
839 }
840
848 {
850 append_suffix ("ul");
851 return *this;
852 }
853
860 expression_formatter::operator<<(signed long long v)
861 {
863 append_suffix ("ll");
864 return *this;
865 }
866
873 expression_formatter::operator<<(unsigned long long v)
874 {
876 append_suffix ("ull");
877 return *this;
878 }
879
889 {
890 const auto start = buffer_.size ();
893 if (std::isfinite (v))
894 {
895 append_suffix ("f");
896 }
897 return *this;
898 }
899
908 {
909 const auto start = buffer_.size ();
912 return *this;
913 }
914
927 {
928 const auto start = buffer_.size ();
931 if (std::isfinite (v))
932 {
933 append_suffix ("L");
934 }
935 return *this;
936 }
937
948 void
950 {
951 if (plain_)
952 {
953 return;
954 }
955 if (start < buffer_.size ()
956 && (buffer_[start] == '-' || buffer_[start] == '+'))
957 {
958 ++start;
959 }
960 if (start == buffer_.size ())
961 {
962 return;
963 }
964 for (auto i = start; i < buffer_.size (); ++i)
965 {
966 if (buffer_[i] < '0' || buffer_[i] > '9')
967 {
968 return;
969 }
970 }
971 buffer_.append (".0");
972 }
973
979 void
981 {
982 if (not plain_)
983 {
984 buffer_.append (suffix);
985 }
986 }
987
994 void
995 expression_formatter::prepend_cast (std::size_t start, const char* type)
996 {
997 if (not plain_)
998 {
999 buffer_.insert (start, type);
1000 }
1001 }
1002
1014 void
1016 char32_t code, std::size_t size)
1017 {
1018 buffer_.append (prefix);
1019 buffer_.push_back ('\'');
1020 switch (code)
1021 {
1022 case U'\0':
1023 buffer_.append ("\\0");
1024 break;
1025 case U'\a':
1026 buffer_.append ("\\a");
1027 break;
1028 case U'\b':
1029 buffer_.append ("\\b");
1030 break;
1031 case U'\t':
1032 buffer_.append ("\\t");
1033 break;
1034 case U'\n':
1035 buffer_.append ("\\n");
1036 break;
1037 case U'\v':
1038 buffer_.append ("\\v");
1039 break;
1040 case U'\f':
1041 buffer_.append ("\\f");
1042 break;
1043 case U'\r':
1044 buffer_.append ("\\r");
1045 break;
1046 case U'\'':
1047 buffer_.append ("\\'");
1048 break;
1049 case U'\\':
1050 buffer_.append ("\\\\");
1051 break;
1052 default:
1053 if (code < 0x20 || code == 0x7F)
1054 {
1055 append_hex (buffer_, code, "\\x", 2);
1056 }
1057 else if (code < 0x7F)
1058 {
1059 buffer_.push_back (static_cast<char> (code));
1060 }
1061 else if (size == 1 || (code >= 0xD800 && code <= 0xDFFF)
1062 || code > 0x10FFFF)
1063 {
1064 append_hex (buffer_, code, "\\x", size * 2);
1065 }
1066 else if (code <= 0xFFFF)
1067 {
1068 append_hex (buffer_, code, "\\u", 4);
1069 }
1070 else
1071 {
1072 append_hex (buffer_, code, "\\U", 8);
1073 }
1074 break;
1075 }
1076 buffer_.push_back ('\'');
1077 }
1078
1079 // --------------------------------------------------------------------------
1080
1088 void
1090 {
1091 if (owner_ != nullptr)
1092 {
1093 pending_.emplace_back (owner_, std::move (buffer_));
1094 }
1095
1096 buffer_.clear ();
1097 owner_ = owner;
1098 }
1099
1106 const std::string&
1107 expression_formatter::check_text (const void* owner) const noexcept
1108 {
1109 if (owner == owner_)
1110 {
1111 return buffer_;
1112 }
1113
1114 for (size_t i = 0; i < pending_.size (); ++i)
1115 {
1116 if (pending_[i].first == owner)
1117 {
1118 return pending_[i].second;
1119 }
1120 }
1121
1122 static const std::string empty{};
1123 return empty;
1124 }
1125
1132 void
1133 expression_formatter::end_check (const void* owner) noexcept
1134 {
1135 if (owner == owner_)
1136 {
1137 owner_ = nullptr;
1138 return;
1139 }
1140
1141 // Use indices and `swap()` + `pop_back()` (both returning void) rather
1142 // than iterators and `erase()`, which returns an iterator object and
1143 // triggers -Waggregate-return; the order of the entries is irrelevant.
1144 for (size_t i = 0; i < pending_.size (); ++i)
1145 {
1146 if (pending_[i].first == owner)
1147 {
1148 if (i + 1 != pending_.size ())
1149 {
1150 pending_[i].swap (pending_.back ());
1151 }
1152 pending_.pop_back ();
1153 return;
1154 }
1155 }
1156 }
1157
1158 // --------------------------------------------------------------------------
1159} // namespace micro_os_plus::micro_test_plus::detail
1160
1161// ----------------------------------------------------------------------------
1162
1163#endif // defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_ENABLED)
1164
1165// ----------------------------------------------------------------------------

Generated via doxygen2docusaurus 2.2.8 by Doxygen 1.18.0.