18 enum class Align { Left, Center, Right };
25 using namespace integral_set_literals;
27 [](concepts::TupleLike
auto result) {
28 auto [fill, align_char] = result;
29 auto align = [](
c32 align_char) {
42 return FillAndAlign { fill, align };
47 enum class Sign { Plus, Minus, Space };
50 using namespace integral_set_literals;
51 return (-
parser::match_one(
'+'_m ||
'-'_m ||
' '_m)) % [](Optional<char32_t> ch) {
52 switch (ch.value_or(U
'-')) {
65 enum class HashTag { Yes, No };
68 using namespace integral_set_literals;
70 return value.has_value() ? HashTag::Yes : HashTag::No;
74 enum class Zero { Yes, No };
77 using namespace integral_set_literals;
79 return value.has_value() ? Zero::Yes : Zero::No;
89 return Width { value };
100 return Precision { value };
105 enum class StringType {
String, Debug };
108 using namespace integral_set_literals;
112 return StringType::String;
114 return StringType::Debug;
121 enum class IntegerType { BinaryLower, BinaryUpper, Character, Decimal, Octal, HexLower, HexUpper };
124 using namespace integral_set_literals;
125 return (-
parser::match_one(
'b'_m ||
'B'_m ||
'c'_m ||
'd'_m ||
'o'_m ||
'x'_m ||
'X'_m)) %
126 [](Optional<char32_t> ch) {
127 switch (ch.value_or(U
'd')) {
129 return IntegerType::BinaryLower;
131 return IntegerType::BinaryUpper;
133 return IntegerType::Character;
135 return IntegerType::Decimal;
137 return IntegerType::Octal;
139 return IntegerType::HexLower;
141 return IntegerType::HexUpper;
148 enum class CharacterType { BinaryLower, BinaryUpper, Character, Decimal, Octal, HexLower, HexUpper, Debug };
151 using namespace integral_set_literals;
152 return (
parser::match_one(
'b'_m ||
'B'_m ||
'c'_m ||
'd'_m ||
'o'_m ||
'x'_m ||
'X'_m ||
'?'_m)) %
156 return CharacterType::BinaryLower;
158 return CharacterType::BinaryUpper;
160 return CharacterType::Character;
162 return CharacterType::Decimal;
164 return CharacterType::Octal;
166 return CharacterType::HexLower;
168 return CharacterType::HexUpper;
170 return CharacterType::Debug;
177 enum class BoolType { BinaryLower, BinaryUpper,
String, Decimal, Octal, HexLower, HexUpper };
180 using namespace integral_set_literals;
181 return (-
parser::match_one(
'b'_m ||
'B'_m ||
'd'_m ||
'o'_m ||
's'_m ||
'x'_m ||
'X'_m)) %
182 [](Optional<char32_t> ch) {
183 switch (ch.value_or(U
's')) {
185 return BoolType::BinaryLower;
187 return BoolType::BinaryUpper;
189 return BoolType::Decimal;
191 return BoolType::Octal;
193 return BoolType::String;
195 return BoolType::HexLower;
197 return BoolType::HexUpper;
204 enum class PointerType { HexLower };
207 using namespace integral_set_literals;
209 switch (ch.value_or(U
'p')) {
211 return PointerType::HexLower;
218 struct StringFormat {
219 Optional<FillAndAlign> fill_and_align;
220 Optional<Width> width;
221 Optional<Precision> precision;
222 Optional<StringType> type;
232 struct IntegerFormat {
233 Optional<FillAndAlign> fill_and_align;
237 Optional<Width> width;
248 struct CharacterFormat {
249 Optional<FillAndAlign> fill_and_align;
253 Optional<Width> width;
254 Optional<CharacterType> type;
265 Optional<FillAndAlign> fill_and_align;
269 Optional<Width> width;
280 struct PointerFormat {
281 Optional<FillAndAlign> fill_and_align;
282 Optional<Width> width;
292 template<concepts::Encoding Enc>
293 constexpr auto present_string_view_to(concepts::FormatContext
auto& context, Optional<FillAndAlign> fill_and_align,
294 Optional<size_t> width, Optional<size_t> precision,
bool debug,
295 container::string::StringViewImpl<Enc> view_in,
301 auto map_to_debug_char = [&](CodePoint p) -> di::StaticVector<
c32, di::Constexpr<4>> {
302 auto result = di::StaticVector<c32, di::Constexpr<4>> {};
304 (void) result.push_back(
c32(p));
307 if (
c32(p) ==
'\0') {
308 (void) result.push_back(U
'\\');
309 (void) result.push_back(U
'0');
310 }
else if (
c32(p) ==
'\a') {
311 (void) result.push_back(U
'\\');
312 (void) result.push_back(U
'a');
313 }
else if (
c32(p) ==
'\b') {
314 (void) result.push_back(U
'\\');
315 (void) result.push_back(U
'b');
316 }
else if (
c32(p) ==
'\f') {
317 (void) result.push_back(U
'\\');
318 (void) result.push_back(U
'f');
319 }
else if (
c32(p) ==
'\n') {
320 (void) result.push_back(U
'\\');
321 (void) result.push_back(U
'n');
322 }
else if (
c32(p) ==
'\r') {
323 (void) result.push_back(U
'\\');
324 (void) result.push_back(U
'r');
325 }
else if (
c32(p) ==
'\t') {
326 (void) result.push_back(U
'\\');
327 (void) result.push_back(U
't');
328 }
else if (
c32(p) ==
'\v') {
329 (void) result.push_back(U
'\\');
330 (void) result.push_back(U
'v');
331 }
else if (
c32(p) ==
'\\') {
332 (void) result.push_back(U
'\\');
333 (void) result.push_back(U
'\\');
336 else if (
c32(p) == delimit_code_point) {
337 (void) result.push_back(U
'\\');
338 (void) result.push_back(delimit_code_point);
342 else if (p <= 31 || p == 127 || (p >= 0x80 && p <= 0x9F)) {
343 auto v1 = (
u8(p) / 16) & 0xF;
344 auto v2 = (
u8(p) % 16);
346 (void) result.push_back(U
'\\');
347 (void) result.push_back(U
'x');
348 (void) result.push_back((v1 >= 10) ? (
'a' + (v1 - 10)) : (
'0' + v1));
349 (void) result.push_back((v2 >= 10) ? (
'a' + (v2 - 10)) : (
'0' + v2));
351 (void) result.push_back(
c32(p));
357 auto view = view::concat(delimit, view::join(view::transform(view_in, map_to_debug_char)), delimit);
359 auto measure_code_point = [&](CodePoint) ->
size_t {
366 (void) context.output(code_point);
370 size_t width_printed_so_far = 0;
375 return do_output_char(code_point);
379 auto code_point_width = measure_code_point(code_point);
380 if (width_printed_so_far + code_point_width > *precision) {
384 auto result = do_output_char(code_point);
385 width_printed_so_far += code_point_width;
393 auto total_width = view | view::transform(measure_code_point) |
container::sum;
394 if (total_width >= *width) {
398 auto align = fill_and_align.transform(&FillAndAlign::align).value_or(FillAndAlign::Align::Left);
399 auto fill_code_point = fill_and_align.transform(&FillAndAlign::fill).value_or(U
' ');
401 auto chars_to_pad = (*width - total_width) / measure_code_point(fill_code_point);
402 auto [left_pad, right_pad] = [&]() -> Tuple<size_t, size_t> {
404 case FillAndAlign::Align::Left:
405 return { 0, chars_to_pad };
406 case FillAndAlign::Align::Center:
408 case FillAndAlign::Align::Right:
409 return { chars_to_pad, 0 };
415 auto do_pad = [&](
auto) {
416 return output_char(fill_code_point);
424 template<concepts::Encoding Enc>
425 constexpr auto present_character_to(concepts::FormatContext
auto& context, Optional<FillAndAlign> fill_and_align,
427 auto encoding = context.encoding();
431 auto as_string_view = container::string::StringViewImpl<Enc> {
first,
last, encoding };
432 return present_string_view_to(context, fill_and_align, width,
nullopt, debug, as_string_view, U
'\'');
435 template<concepts::Encoding Enc, concepts::Integral T>
436 constexpr auto present_integer_to(concepts::FormatContext
auto& context, Optional<FillAndAlign> fill_and_align,
437 Sign sign, HashTag hash_tag, Zero zero, Optional<size_t> width, IntegerType type,
439 if (type == IntegerType::Character) {
440 return present_character_to<Enc>(context, fill_and_align, width, debug,
static_cast<c32>(value));
447 auto buffer = container::string::StringImpl<
448 Enc, container::StaticVector<meta::EncodingCodeUnit<Enc>, meta::Constexpr<67ZU>>> {};
453 auto const negative = [&] {
454 if constexpr (concepts::Signed<T>) {
464 (void) buffer.push_back(CodePoint(
'-'));
469 (void) buffer.push_back(CodePoint(
'-'));
471 (void) buffer.push_back(CodePoint(
'+'));
476 (void) buffer.push_back(CodePoint(
'-'));
478 (void) buffer.push_back(CodePoint(
' '));
484 auto do_prefix = [&] {
485 if (hash_tag == HashTag::No) {
489 case IntegerType::BinaryLower:
490 (void) buffer.push_back(CodePoint(
'0'));
491 (void) buffer.push_back(CodePoint(
'b'));
493 case IntegerType::BinaryUpper:
494 (void) buffer.push_back(CodePoint(
'0'));
495 (void) buffer.push_back(CodePoint(
'B'));
497 case IntegerType::Octal:
498 (void) buffer.push_back(CodePoint(
'0'));
500 case IntegerType::HexLower:
501 (void) buffer.push_back(CodePoint(
'0'));
502 (void) buffer.push_back(CodePoint(
'x'));
504 case IntegerType::HexUpper:
505 (void) buffer.push_back(CodePoint(
'0'));
506 (void) buffer.push_back(CodePoint(
'X'));
513 bool zero_pad = zero == Zero::Yes && !fill_and_align;
519 for (
auto ch : buffer) {
523 if (width && *width > code_points) {
524 *width -= code_points;
529 auto const radix = [&] -> UnsignedType {
531 case IntegerType::BinaryLower:
532 case IntegerType::BinaryUpper:
534 case IntegerType::Octal:
536 case IntegerType::HexLower:
537 case IntegerType::HexUpper:
546 case IntegerType::HexLower:
547 return (value >= 10) ? (
'a' + (
value - 10)) : (
'0' +
value);
548 case IntegerType::HexUpper:
549 return (value >= 10) ? (
'A' + (value - 10)) : (
'0' + value);
551 return (
'0' + value);
555 UnsignedType strength = 1;
556 for (
auto x = as_unsigned; x / strength >= radix; strength *= radix) {}
558 for (; strength; strength /= radix) {
559 (void) buffer.push_back(to_digit((as_unsigned / strength) % radix));
562 auto backup_fill_and_align = FillAndAlign { zero_pad ? U
'0' : U
' ', FillAndAlign::Align::Right };
563 return present_string_view_to<Enc>(context, fill_and_align.value_or(backup_fill_and_align), width,
nullopt,
567 template<concepts::Encoding Enc>
568 constexpr auto present_formatted_to(concepts::FormatContext
auto& context, Optional<FillAndAlign> fill_and_align,
569 Optional<size_t> width, Optional<size_t> precision,
570 container::string::StringViewImpl<Enc> format_string,
auto&&... args)
590 (void) fill_and_align;
#define DI_ASSERT(...)
Definition assert_bool.h:7
#define DI_TRY(...)
Definition monad_try.h:13
constexpr auto convert_to_code_units
Definition encoding.h:139
constexpr auto code_point_view
Definition encoding.h:159
constexpr auto last(concepts::detail::ConstantVector auto &vector, size_t count)
Definition vector_last.h:13
constexpr auto first(concepts::detail::ConstantVector auto &vector, size_t count)
Definition vector_first.h:13
string::StringImpl< string::Utf8Encoding > String
Definition string.h:11
constexpr auto sequence
Definition sequence.h:34
constexpr auto distance
Definition distance.h:44
constexpr auto sum
Definition sum.h:26
constexpr auto value
Definition value.h:34
constexpr auto to_unsigned
Definition to_unsigned.h:16
constexpr auto divide_round_up
Definition divide_round_up.h:17
constexpr auto abs_unsigned
Definition abs_unsigned.h:26
constexpr auto code_point
Definition code_point_parser.h:35
constexpr auto match_one
Definition match_one.h:27
constexpr auto integer
Definition integer.h:212
__UINT8_TYPE__ u8
Definition integers.h:9
char32_t c32
Definition char.h:6
di::meta::Decay< decltype(T)> Tag
Definition tag_invoke.h:28
void unreachable()
Definition unreachable.h:4
Expected< T, Error > Result
Definition result.h:8
constexpr auto create_parser
Definition create_parser.h:55
constexpr tag_invoke_detail::TagInvokeFn tag_invoke
Definition tag_invoke.h:22
constexpr auto make_from_tuple
Definition make_from_tuple.h:31
constexpr auto nullopt
Definition nullopt.h:15
constexpr auto lift_bool
Definition lift_bool.h:13