libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
writer.hpp
1#pragma once
2
3#include <array>
4#include <bit>
5#include <cmath>
6#include <concepts>
7#include <cstddef>
8#include <cstdint>
9#include <cstring>
10#include <limits>
11#include <string>
12#include <string_view>
13#include <tuple>
14#include <type_traits>
15#include <utility>
16
17#include "format_argument.hpp"
18#include "format_protocol.hpp"
19#include "libxr_def.hpp"
20#include "print_contract.hpp"
21
22namespace LibXR::Print
23{
28class Writer
29{
30 public:
42 template <typename Sink, typename Format, auto ArgumentOrder, typename... Args>
44 [[nodiscard]] static ErrorCode RunArgumentOrder(Sink& sink, const Format&, Args&&... args)
45 {
46 using Built = std::remove_cvref_t<Format>;
47 static_assert(ArgumentOrder.size() == Built::ArgumentList().size(),
48 "LibXR::Print::Writer: argument reorder list must match the "
49 "compiled field count");
50 static_assert(Built::template Matches<Args...>(),
51 "LibXR::Print::Writer::RunArgumentOrder: format arguments do not match");
52
53 return RunTaggedArgumentOrder<Sink, Built::ArgumentList(), ArgumentOrder,
54 Built::Profile()>(
55 sink, Built::Codes().data(), std::forward<Args>(args)...);
56 }
57
58 private:
63 static constexpr uint8_t unspecified_precision = 0xFF;
64 static constexpr size_t float_buffer_capacity = 512;
65 template <FormatPackKind K>
66 static constexpr bool dependent_false_v = false;
68 static constexpr float f32_u32_overflow_limit = 4294967296.0f;
70 inline static constexpr std::array<uint32_t, 10> f32_decimal_scales_u32{
71 1U,
72 10U,
73 100U,
74 1000U,
75 10000U,
76 100000U,
77 1000000U,
78 10000000U,
79 100000000U,
80 1000000000U,
81 };
82
87 [[nodiscard]] static constexpr bool HasFlag(uint8_t flags, uint8_t bit)
88 {
89 return (flags & bit) != 0;
90 }
91
96 struct Spec
97 {
98 uint8_t flags = 0;
99 char fill = ' ';
100 uint8_t width = 0;
101 uint8_t precision =
103
104 [[nodiscard]] constexpr bool LeftAlign() const
105 {
106 return Writer::HasFlag(flags, static_cast<uint8_t>(FormatFlag::LeftAlign));
107 }
108
109 [[nodiscard]] constexpr bool ForceSign() const
110 {
111 return Writer::HasFlag(flags, static_cast<uint8_t>(FormatFlag::ForceSign));
112 }
113
114 [[nodiscard]] constexpr bool CenterAlign() const
115 {
116 return Writer::HasFlag(flags, static_cast<uint8_t>(FormatFlag::CenterAlign));
117 }
118
119 [[nodiscard]] constexpr bool SpaceSign() const
120 {
121 return Writer::HasFlag(flags, static_cast<uint8_t>(FormatFlag::SpaceSign));
122 }
123
124 [[nodiscard]] constexpr bool Alternate() const
125 {
126 return Writer::HasFlag(flags, static_cast<uint8_t>(FormatFlag::Alternate));
127 }
128
129 [[nodiscard]] constexpr bool ZeroPad() const
130 {
131 return Writer::HasFlag(flags, static_cast<uint8_t>(FormatFlag::ZeroPad));
132 }
133
134 [[nodiscard]] constexpr bool UpperCase() const
135 {
136 return Writer::HasFlag(flags, static_cast<uint8_t>(FormatFlag::UpperCase));
137 }
138
139 [[nodiscard]] constexpr bool HasPrecision() const
140 {
142 }
143 };
144
145 template <typename T>
146 [[nodiscard]] static constexpr std::string_view ToStringView(const T& text)
147 {
148 using Traits = Detail::FormatArgument::TypeTraits<T>;
149
150 if constexpr (std::is_same_v<typename Traits::Decayed, std::string_view>)
151 {
152 return text;
153 }
154 else if constexpr (std::is_same_v<typename Traits::Decayed, std::string>)
155 {
156 return std::string_view(text.data(), text.size());
157 }
158 else if constexpr (std::is_same_v<typename Traits::Decayed, const char*> ||
159 std::is_same_v<typename Traits::Decayed, char*>)
160 {
161 if (text == nullptr)
162 {
163 return "(null)";
164 }
165 return std::string_view(text, std::strlen(text));
166 }
167 else if constexpr (Traits::is_char_array)
168 {
169 return std::string_view(text, std::strlen(text));
170 }
171 else
172 {
173 return {};
174 }
175 }
176
182 template <FormatPackKind pack, typename T>
183 [[nodiscard]] static constexpr auto PackValue(T&& value)
184 {
186 using Normalized = typename Traits::Normalized;
187
188 if constexpr (pack == FormatPackKind::I32)
189 {
190 if constexpr (Traits::is_signed_integer)
191 {
192 return static_cast<int32_t>(static_cast<Normalized>(value));
193 }
194 }
195 else if constexpr (pack == FormatPackKind::I64)
196 {
197 if constexpr (Traits::is_signed_integer)
198 {
199 return static_cast<int64_t>(static_cast<Normalized>(value));
200 }
201 }
202 else if constexpr (pack == FormatPackKind::U32)
203 {
204 if constexpr (std::is_same_v<Normalized, bool>)
205 {
206 return static_cast<uint32_t>(value ? 1U : 0U);
207 }
208 else if constexpr (std::is_integral_v<Normalized>)
209 {
210 return static_cast<uint32_t>(static_cast<std::make_unsigned_t<Normalized>>(
211 static_cast<Normalized>(value)));
212 }
213 }
214 else if constexpr (pack == FormatPackKind::U64)
215 {
216 if constexpr (std::is_same_v<Normalized, bool>)
217 {
218 return static_cast<uint64_t>(value ? 1U : 0U);
219 }
220 else if constexpr (std::is_integral_v<Normalized>)
221 {
222 return static_cast<uint64_t>(static_cast<std::make_unsigned_t<Normalized>>(
223 static_cast<Normalized>(value)));
224 }
225 }
226 else if constexpr (pack == FormatPackKind::Pointer)
227 {
228 if constexpr (Traits::is_pointer_like)
229 {
230 if constexpr (std::is_same_v<typename Traits::Decayed, std::nullptr_t>)
231 {
232 return static_cast<uintptr_t>(0);
233 }
234 else
235 {
236 return (value == nullptr) ? static_cast<uintptr_t>(0)
237 : reinterpret_cast<uintptr_t>(value);
238 }
239 }
240 }
241 else if constexpr (pack == FormatPackKind::Character)
242 {
243 if constexpr (Traits::is_character_like)
244 {
245 return static_cast<char>(static_cast<Normalized>(value));
246 }
247 }
248 else if constexpr (pack == FormatPackKind::StringView)
249 {
250 if constexpr (Traits::is_string_like)
251 {
252 return ToStringView(value);
253 }
254 }
255 else if constexpr (pack == FormatPackKind::F32)
256 {
257 if constexpr (std::is_arithmetic_v<Normalized>)
258 {
259 return static_cast<float>(value);
260 }
261 }
262 else if constexpr (pack == FormatPackKind::F64)
263 {
264 if constexpr (std::is_arithmetic_v<Normalized>)
265 {
266 return static_cast<double>(value);
267 }
268 }
269 else if constexpr (pack == FormatPackKind::LongDouble)
270 {
271 if constexpr (std::is_arithmetic_v<Normalized>)
272 {
273 return static_cast<long double>(value);
274 }
275 }
276 else
277 {
278 static_assert(dependent_false_v<pack>,
279 "LibXR::Print::Writer::PackValue: unsupported packed argument kind");
280 }
281 }
282
283 template <typename T>
284 static void StoreArgument(uint8_t*& out, const T& value)
285 {
286 std::memcpy(out, &value, sizeof(T));
287 out += sizeof(T);
288 }
289
290 template <auto ArgumentInfoList>
291 [[nodiscard]] static consteval size_t PackedArgumentBytes()
292 {
293 size_t bytes = 0;
294 for (const auto& argument : ArgumentInfoList)
295 {
296 bytes += FormatArgumentBytes(argument.pack);
297 }
298 return bytes;
299 }
300
301 template <auto ArgumentInfoList, auto ArgumentOrder, typename Tuple>
302 static void StoreArgumentsOrdered(uint8_t*& out, Tuple& tuple)
303 {
304 [&]<size_t... I>(std::index_sequence<I...>) {
305 (StoreArgument(out, PackValue<ArgumentInfoList[I].pack>(
306 std::get<ArgumentOrder[I]>(tuple))),
307 ...);
308 }(std::make_index_sequence<ArgumentInfoList.size()>{});
309 }
310
311 template <std::unsigned_integral UInt>
312 [[nodiscard]] static size_t AppendUnsigned(char* out, UInt value, uint8_t base,
313 bool upper_case)
314 {
315 constexpr char lower_digits[] = "0123456789abcdef";
316 constexpr char upper_digits[] = "0123456789ABCDEF";
317 const char* digits = upper_case ? upper_digits : lower_digits;
318 char reverse[32];
319 size_t count = 0;
320
321 if (value == 0)
322 {
323 out[0] = '0';
324 return 1;
325 }
326
327 while (value != 0)
328 {
329 reverse[count++] = digits[value % base];
330 value /= base;
331 }
332
333 for (size_t i = 0; i < count; ++i)
334 {
335 out[i] = reverse[count - i - 1];
336 }
337
338 return count;
339 }
340
341 [[nodiscard]] static size_t AppendSmallUnsigned(char* out, uint8_t value)
342 {
343 return AppendUnsigned(out, value, 10, false);
344 }
345
347 [[nodiscard]] static constexpr size_t FieldPadding(uint8_t width, size_t payload_size)
348 {
349 return (width > payload_size) ? static_cast<size_t>(width) - payload_size : 0;
350 }
351
353 [[nodiscard]] static constexpr size_t IntegerPrecisionZeros(
354 const Spec& spec, size_t digit_count)
355 {
356 return (spec.HasPrecision() && spec.precision > digit_count)
357 ? static_cast<size_t>(spec.precision) - digit_count
358 : 0;
359 }
360
362 [[nodiscard]] static constexpr uint8_t IntegerBase(FormatType type)
363 {
364 switch (type)
365 {
366 case FormatType::Unsigned32:
367 case FormatType::Unsigned64:
368 return 10;
369 case FormatType::Binary32:
370 case FormatType::Binary64:
371 return 2;
372 case FormatType::Octal32:
373 case FormatType::Octal64:
374 return 8;
375 case FormatType::HexLower32:
376 case FormatType::HexLower64:
377 case FormatType::HexUpper32:
378 case FormatType::HexUpper64:
379 return 16;
380 default:
381 return 0;
382 }
383 }
384
386 [[nodiscard]] static constexpr bool IntegerUpperCase(FormatType type)
387 {
388 return type == FormatType::HexUpper32 || type == FormatType::HexUpper64;
389 }
390
392 template <std::unsigned_integral UInt>
393 [[nodiscard]] static constexpr std::string_view IntegerPrefix(
394 FormatType type, const Spec& spec, UInt value)
395 {
396 if (!spec.Alternate() || value == 0)
397 {
398 return {};
399 }
400 if (type == FormatType::HexLower32 || type == FormatType::HexLower64)
401 {
402 return "0x";
403 }
404 if (type == FormatType::HexUpper32 || type == FormatType::HexUpper64)
405 {
406 return "0X";
407 }
408 if (type == FormatType::Binary32 || type == FormatType::Binary64)
409 {
410 return spec.UpperCase() ? "0B" : "0b";
411 }
412 return {};
413 }
414
426 template <std::unsigned_integral UInt>
427 [[nodiscard]] static size_t ApplyAlternateOctal(char* digits, size_t digit_count,
428 const Spec& spec, UInt value)
429 {
430 if (!spec.Alternate())
431 {
432 return (value == 0 && spec.precision == 0) ? 0 : digit_count;
433 }
434
435 if (value == 0 && spec.precision == 0)
436 {
437 return 1;
438 }
439
440 if (value == 0)
441 {
442 return digit_count;
443 }
444
445 if (spec.HasPrecision() && spec.precision > digit_count)
446 {
447 return digit_count;
448 }
449
450 digits[digit_count++] = '0';
451 for (size_t i = digit_count - 1; i > 0; --i)
452 {
453 digits[i] = digits[i - 1];
454 }
455 digits[0] = '0';
456 return digit_count;
457 }
458
460 [[nodiscard]] static constexpr bool UsesFloatTextBackend(FormatType type)
461 {
462 switch (type)
463 {
464 case FormatType::FloatScientific:
465 case FormatType::DoubleScientific:
466 case FormatType::LongDoubleScientific:
467 case FormatType::FloatGeneral:
468 case FormatType::DoubleGeneral:
469 case FormatType::LongDoubleGeneral:
470 case FormatType::FloatFixed:
471 case FormatType::DoubleFixed:
472 case FormatType::LongDoubleFixed:
473 return true;
474 default:
475 return false;
476 }
477 }
478
480 [[nodiscard]] static constexpr bool FloatEnabled(FormatType type)
481 {
482 switch (type)
483 {
484 case FormatType::FloatFixed:
485 return Config::enable_float_fixed;
486 case FormatType::FloatScientific:
487 return Config::enable_float_scientific;
488 case FormatType::FloatGeneral:
489 return Config::enable_float_general;
490 case FormatType::DoubleFixed:
491 return Config::enable_float_double && Config::enable_float_fixed;
492 case FormatType::DoubleScientific:
493 return Config::enable_float_double && Config::enable_float_scientific;
494 case FormatType::DoubleGeneral:
495 return Config::enable_float_double && Config::enable_float_general;
496 case FormatType::LongDoubleFixed:
497 return Config::enable_float_long_double && Config::enable_float_fixed;
498 case FormatType::LongDoubleScientific:
499 return Config::enable_float_long_double && Config::enable_float_scientific;
500 case FormatType::LongDoubleGeneral:
501 return Config::enable_float_long_double && Config::enable_float_general;
502 default:
503 return false;
504 }
505 }
506
508 [[nodiscard]] static bool AppendBufferChar(char* buffer, size_t capacity, size_t& size,
509 char ch)
510 {
511 if (size >= capacity)
512 {
513 return false;
514 }
515 buffer[size++] = ch;
516 return true;
517 }
518
520 [[nodiscard]] static bool AppendBufferText(char* buffer, size_t capacity, size_t& size,
521 std::string_view text)
522 {
523 if (text.size() > capacity - size)
524 {
525 return false;
526 }
527 std::memcpy(buffer + size, text.data(), text.size());
528 size += text.size();
529 return true;
530 }
531
533 [[nodiscard]] static bool AppendBufferU32ZeroPad(char* buffer, size_t capacity,
534 size_t& size, uint32_t value,
535 uint8_t width)
536 {
537 char digits[10];
538 size_t digit_count = AppendUnsigned(digits, value, 10, false);
539 size_t zero_count = (width > digit_count) ? static_cast<size_t>(width) - digit_count : 0;
540
541 for (size_t i = 0; i < zero_count; ++i)
542 {
543 if (!AppendBufferChar(buffer, capacity, size, '0'))
544 {
545 return false;
546 }
547 }
548
549 return AppendBufferText(buffer, capacity, size, std::string_view(digits, digit_count));
550 }
551
553 [[nodiscard]] static uint64_t RoundScaledF32(float value, uint32_t scale)
554 {
555 uint32_t bits = std::bit_cast<uint32_t>(value);
556 uint32_t exponent_bits = (bits >> 23) & 0xFFU;
557 uint32_t fraction_bits = bits & 0x7FFFFFU;
558 uint32_t significand =
559 (exponent_bits == 0) ? fraction_bits : ((1U << 23) | fraction_bits);
560 int exponent2 =
561 (exponent_bits == 0) ? -149 : static_cast<int>(exponent_bits) - 150;
562 uint64_t numerator = static_cast<uint64_t>(significand) * scale;
563
564 if (exponent2 >= 0)
565 {
566 return numerator << exponent2;
567 }
568
569 unsigned int shift = static_cast<unsigned int>(-exponent2);
570 if (shift >= 64)
571 {
572 return 0;
573 }
574 uint64_t quotient = numerator >> shift;
575 uint64_t remainder = numerator & ((uint64_t{1} << shift) - 1U);
576 uint64_t halfway = uint64_t{1} << (shift - 1);
577 if (remainder > halfway || (remainder == halfway && (quotient & 1U) != 0U))
578 {
579 ++quotient;
580 }
581 return quotient;
582 }
583
584 template <typename Float>
586 {
587 int exponent = 0;
588 Float scale = 1;
589 };
590
591 template <typename Float>
592 [[nodiscard]] static Float Power10(int exponent)
593 {
594 Float result = 1;
595 Float base = 10;
596 unsigned int remaining =
597 static_cast<unsigned int>(exponent < 0 ? -exponent : exponent);
598
599 while (remaining != 0)
600 {
601 if ((remaining & 1U) != 0U)
602 {
603 if (exponent < 0)
604 {
605 result /= base;
606 }
607 else
608 {
609 result *= base;
610 }
611 }
612
613 remaining >>= 1U;
614 if (remaining != 0U)
615 {
616 base *= base;
617 }
618 }
619
620 return result;
621 }
622
624 template <typename Float>
625 [[nodiscard]] static DecimalScale<Float> NormalizeDecimal(Float value)
626 {
627 DecimalScale<Float> normalized{};
628 if (value == 0)
629 {
630 return normalized;
631 }
632
633 int binary_exponent = 0;
634 std::frexp(value, &binary_exponent);
635 constexpr Float log10_of_2 =
636 static_cast<Float>(0.30102999566398119521373889472449L);
637 normalized.exponent =
638 static_cast<int>(static_cast<Float>(binary_exponent - 1) * log10_of_2);
639 normalized.scale = Power10<Float>(normalized.exponent);
640
641 Float scaled = value / normalized.scale;
642 while (scaled < 1)
643 {
644 normalized.scale /= 10;
645 --normalized.exponent;
646 scaled *= 10;
647 }
648 while (scaled >= 10)
649 {
650 normalized.scale *= 10;
651 ++normalized.exponent;
652 scaled /= 10;
653 }
654
655 return normalized;
656 }
657
659 template <typename Float>
660 [[nodiscard]] static uint8_t ExtractDigit(Float& value, Float scale)
661 {
662 Float scaled = value / scale;
663 auto digit = static_cast<int>(scaled + static_cast<Float>(1e-12L));
664 if (digit < 0)
665 {
666 digit = 0;
667 }
668 else if (digit > 9)
669 {
670 digit = 9;
671 }
672
673 value -= static_cast<Float>(digit) * scale;
674 Float epsilon = scale * static_cast<Float>(1e-9L);
675 if (value < 0 && value > -epsilon)
676 {
677 value = 0;
678 }
679
680 return static_cast<uint8_t>(digit);
681 }
682
684 [[nodiscard]] static size_t TrimGeneralText(char* text, size_t size)
685 {
686 size_t exponent_pos = size;
687 for (size_t i = 0; i < size; ++i)
688 {
689 if (text[i] == 'e' || text[i] == 'E')
690 {
691 exponent_pos = i;
692 break;
693 }
694 }
695
696 size_t mantissa_end = exponent_pos;
697 while (mantissa_end > 0 && text[mantissa_end - 1] == '0')
698 {
699 --mantissa_end;
700 }
701 if (mantissa_end > 0 && text[mantissa_end - 1] == '.')
702 {
703 --mantissa_end;
704 }
705
706 if (exponent_pos == size)
707 {
708 return mantissa_end;
709 }
710
711 std::memmove(text + mantissa_end, text + exponent_pos, size - exponent_pos);
712 return mantissa_end + (size - exponent_pos);
713 }
714
716 [[nodiscard]] static bool FormatF32FixedPrecText(float value, uint8_t precision,
717 char* out, size_t& out_size)
718 {
719 out_size = 0;
720
721 // Stage 1: special IEEE spellings.
722 // 第 1 阶段:处理 IEEE 特殊值文本。
723 if (std::isnan(value))
724 {
725 return AppendBufferText(out, float_buffer_capacity, out_size, "nan");
726 }
727 if (std::isinf(value))
728 {
729 return AppendBufferText(out, float_buffer_capacity, out_size, "inf");
730 }
731
732 // Stage 2: narrow uint32_t-backed fixed formatter for the common case.
733 // 第 2 阶段:常见场景优先走基于 uint32_t 的窄定点格式化器。
734 if (precision < f32_decimal_scales_u32.size() && value < f32_u32_overflow_limit)
735 {
736 uint32_t integer_part = static_cast<uint32_t>(value);
737 uint32_t scale = f32_decimal_scales_u32[precision];
738 uint64_t scaled_total = RoundScaledF32(value, scale);
739 uint64_t scaled_integer = static_cast<uint64_t>(integer_part) * scale;
740 uint32_t fractional_part =
741 (scaled_total >= scaled_integer)
742 ? static_cast<uint32_t>(scaled_total - scaled_integer)
743 : 0U;
744
745 if (fractional_part >= scale)
746 {
747 fractional_part -= scale;
748 if (integer_part == std::numeric_limits<uint32_t>::max())
749 {
750 if (!AppendBufferText(out, float_buffer_capacity, out_size, "4294967296"))
751 {
752 return false;
753 }
754 if (precision == 0)
755 {
756 return true;
757 }
758 if (!AppendBufferChar(out, float_buffer_capacity, out_size, '.'))
759 {
760 return false;
761 }
762 for (uint8_t i = 0; i < precision; ++i)
763 {
764 if (!AppendBufferChar(out, float_buffer_capacity, out_size, '0'))
765 {
766 return false;
767 }
768 }
769 return true;
770 }
771 ++integer_part;
772 }
773
774 if (!AppendBufferU32ZeroPad(out, float_buffer_capacity, out_size, integer_part, 1))
775 {
776 return false;
777 }
778 if (precision == 0)
779 {
780 return true;
781 }
782 if (!AppendBufferChar(out, float_buffer_capacity, out_size, '.'))
783 {
784 return false;
785 }
786 return AppendBufferU32ZeroPad(out, float_buffer_capacity, out_size, fractional_part,
787 precision);
788 }
789
790 // Stage 3: generic fixed-only fallback for larger precision or magnitude.
791 // 第 3 阶段:针对更大精度或更大数量级的通用仅定点回退路径。
792 float rounded = value;
793 float rounding = 0.5f;
794 for (uint8_t i = 0; i < precision; ++i)
795 {
796 rounding *= 0.1f;
797 }
798 rounded += rounding;
799
800 if (rounded < 1.0f)
801 {
802 if (!AppendBufferChar(out, float_buffer_capacity, out_size, '0'))
803 {
804 return false;
805 }
806 }
807 else
808 {
809 float integer_scale = 1.0f;
810 while (true)
811 {
812 float next_scale = integer_scale * 10.0f;
813 if (!std::isfinite(next_scale) || rounded < next_scale)
814 {
815 break;
816 }
817 integer_scale = next_scale;
818 }
819
820 while (integer_scale >= 1.0f)
821 {
822 int digit = static_cast<int>(rounded / integer_scale);
823 if (digit < 0)
824 {
825 digit = 0;
826 }
827 else if (digit > 9)
828 {
829 digit = 9;
830 }
831
832 if (!AppendBufferChar(out, float_buffer_capacity, out_size,
833 static_cast<char>('0' + digit)))
834 {
835 return false;
836 }
837
838 rounded -= static_cast<float>(digit) * integer_scale;
839 float epsilon = integer_scale * 1e-6f;
840 if (rounded < 0.0f && rounded > -epsilon)
841 {
842 rounded = 0.0f;
843 }
844 integer_scale *= 0.1f;
845 }
846 }
847
848 if (precision == 0)
849 {
850 return true;
851 }
852 if (!AppendBufferChar(out, float_buffer_capacity, out_size, '.'))
853 {
854 return false;
855 }
856
857 for (uint8_t i = 0; i < precision; ++i)
858 {
859 rounded *= 10.0f;
860 int digit = static_cast<int>(rounded + 1e-6f);
861 if (digit < 0)
862 {
863 digit = 0;
864 }
865 else if (digit > 9)
866 {
867 digit = 9;
868 }
869
870 if (!AppendBufferChar(out, float_buffer_capacity, out_size,
871 static_cast<char>('0' + digit)))
872 {
873 return false;
874 }
875
876 rounded -= static_cast<float>(digit);
877 if (rounded < 0.0f && rounded > -1e-5f)
878 {
879 rounded = 0.0f;
880 }
881 }
882
883 return true;
884 }
885
886 template <typename Float>
887 [[nodiscard]] static bool FormatFixedText(Float value, uint8_t precision, bool alternate,
888 char* out, size_t& out_size)
889 {
890 Float rounded =
891 value + static_cast<Float>(0.5L) * Power10<Float>(-static_cast<int>(precision));
892 auto normalized = NormalizeDecimal(rounded);
893 int integer_exponent = (rounded == 0) ? 0 : normalized.exponent;
894 int start_pos = (integer_exponent > 0) ? integer_exponent : 0;
895 Float scale = Power10<Float>(start_pos);
896
897 out_size = 0;
898 for (int pos = start_pos; pos >= 0; --pos)
899 {
900 if (!AppendBufferChar(out, float_buffer_capacity, out_size,
901 static_cast<char>('0' + ExtractDigit(rounded, scale))))
902 {
903 return false;
904 }
905 scale /= 10;
906 }
907
908 if (precision != 0 || alternate)
909 {
910 if (!AppendBufferChar(out, float_buffer_capacity, out_size, '.'))
911 {
912 return false;
913 }
914 }
915
916 for (uint8_t i = 0; i < precision; ++i)
917 {
918 if (!AppendBufferChar(out, float_buffer_capacity, out_size,
919 static_cast<char>('0' + ExtractDigit(rounded, scale))))
920 {
921 return false;
922 }
923 scale /= 10;
924 }
925
926 return true;
927 }
928
929 [[nodiscard]] static bool AppendExponentText(char* out, size_t& out_size, int exponent,
930 bool upper_case)
931 {
932 if (!AppendBufferChar(out, float_buffer_capacity, out_size,
933 upper_case ? 'E' : 'e'))
934 {
935 return false;
936 }
937 if (!AppendBufferChar(out, float_buffer_capacity, out_size,
938 exponent < 0 ? '-' : '+'))
939 {
940 return false;
941 }
942
943 char digits[16];
944 unsigned int magnitude =
945 static_cast<unsigned int>(exponent < 0 ? -exponent : exponent);
946 size_t digit_count = AppendUnsigned(digits, magnitude, 10, false);
947 if (digit_count < 2 &&
948 !AppendBufferChar(out, float_buffer_capacity, out_size, '0'))
949 {
950 return false;
951 }
952
953 return AppendBufferText(out, float_buffer_capacity, out_size,
954 std::string_view(digits, digit_count));
955 }
956
957 template <typename Float>
958 [[nodiscard]] static bool FormatScientificText(Float value, uint8_t precision,
959 bool alternate, bool upper_case, char* out,
960 size_t& out_size)
961 {
962 auto initial = NormalizeDecimal(value);
963 Float rounded = value;
964 if (value != 0)
965 {
966 rounded += static_cast<Float>(0.5L) *
967 Power10<Float>(initial.exponent - static_cast<int>(precision));
968 }
969
970 auto normalized = NormalizeDecimal(rounded);
971 int exponent = (rounded == 0) ? 0 : normalized.exponent;
972 Float scale = Power10<Float>(exponent);
973
974 out_size = 0;
975 if (!AppendBufferChar(out, float_buffer_capacity, out_size,
976 static_cast<char>('0' + ExtractDigit(rounded, scale))))
977 {
978 return false;
979 }
980
981 if (precision != 0 || alternate)
982 {
983 if (!AppendBufferChar(out, float_buffer_capacity, out_size, '.'))
984 {
985 return false;
986 }
987 }
988
989 scale /= 10;
990 for (uint8_t i = 0; i < precision; ++i)
991 {
992 if (!AppendBufferChar(out, float_buffer_capacity, out_size,
993 static_cast<char>('0' + ExtractDigit(rounded, scale))))
994 {
995 return false;
996 }
997 scale /= 10;
998 }
999
1000 return AppendExponentText(out, out_size, exponent, upper_case);
1001 }
1002
1003 template <typename Float>
1004 [[nodiscard]] static bool FormatFloatText(FormatType type, const Spec& spec, Float value,
1005 char* out, size_t& out_size)
1006 {
1007 out_size = 0;
1008
1009 if (std::isnan(value))
1010 {
1011 return AppendBufferText(out, float_buffer_capacity, out_size,
1012 spec.UpperCase() ? "NAN" : "nan");
1013 }
1014 if (std::isinf(value))
1015 {
1016 return AppendBufferText(out, float_buffer_capacity, out_size,
1017 spec.UpperCase() ? "INF" : "inf");
1018 }
1019
1020 uint8_t precision = spec.HasPrecision() ? spec.precision : 6;
1021 switch (type)
1022 {
1023 case FormatType::FloatFixed:
1024 case FormatType::DoubleFixed:
1025 case FormatType::LongDoubleFixed:
1026 return FormatFixedText(value, precision, spec.Alternate(), out, out_size);
1027 case FormatType::FloatScientific:
1028 case FormatType::DoubleScientific:
1029 case FormatType::LongDoubleScientific:
1030 return FormatScientificText(value, precision, spec.Alternate(), spec.UpperCase(),
1031 out, out_size);
1032 case FormatType::FloatGeneral:
1033 case FormatType::DoubleGeneral:
1034 case FormatType::LongDoubleGeneral:
1035 {
1036 uint8_t significant = precision == 0 ? 1 : precision;
1037 int exponent = (value == 0) ? 0 : NormalizeDecimal(value).exponent;
1038 if (exponent < -4 || exponent >= significant)
1039 {
1040 if (!FormatScientificText(value, static_cast<uint8_t>(significant - 1),
1041 spec.Alternate(), spec.UpperCase(), out, out_size))
1042 {
1043 return false;
1044 }
1045 }
1046 else
1047 {
1048 int fractional_precision = static_cast<int>(significant) - (exponent + 1);
1049 if (fractional_precision < 0)
1050 {
1051 fractional_precision = 0;
1052 }
1053 if (!FormatFixedText(value, static_cast<uint8_t>(fractional_precision),
1054 spec.Alternate(), out, out_size))
1055 {
1056 return false;
1057 }
1058 }
1059
1060 if (!spec.Alternate())
1061 {
1062 out_size = TrimGeneralText(out, out_size);
1063 }
1064 return true;
1065 }
1066 default:
1067 return false;
1068 }
1069 }
1070
1071 class CodeReader;
1072 class ArgumentReader;
1073
1074 template <OutputSink Sink, FormatProfile Profile>
1075 class Executor;
1076
1077 template <OutputSink Sink, FormatProfile Profile>
1078 [[nodiscard]] __attribute__((noinline)) static ErrorCode Execute(
1079 Sink& sink, const uint8_t* codes, const uint8_t* args)
1080 {
1081 return Executor<Sink, Profile>(sink, codes, args).Run();
1082 }
1083
1084 template <OutputSink Sink, auto ArgumentInfoList, auto ArgumentOrder,
1085 FormatProfile Profile, typename... Args>
1086 [[nodiscard]] __attribute__((noinline)) static ErrorCode RunTaggedArgumentOrder(
1087 Sink& sink, const uint8_t* codes, Args&&... args)
1088 {
1089 if constexpr (ArgumentInfoList.size() == 0)
1090 {
1091 return Execute<Sink, Profile>(sink, codes, nullptr);
1092 }
1093 else
1094 {
1095 constexpr size_t packed_arg_bytes = PackedArgumentBytes<ArgumentInfoList>();
1096 uint8_t packed[packed_arg_bytes];
1097 auto tuple = std::forward_as_tuple(std::forward<Args>(args)...);
1098 auto* cursor = packed;
1099 StoreArgumentsOrdered<ArgumentInfoList, ArgumentOrder>(cursor, tuple);
1100 return Execute<Sink, Profile>(sink, codes, packed);
1101 }
1102 }
1103};
1104
1110{
1111 public:
1113 explicit CodeReader(const uint8_t* codes) : pos_(codes), base_(codes)
1114 {
1115 }
1116
1118 [[nodiscard]] FormatOp ReadOp() { return static_cast<FormatOp>(*pos_++); }
1119
1121 template <typename T>
1122 [[nodiscard]] T Read()
1123 {
1124 T value{};
1125 std::memcpy(&value, pos_, sizeof(T));
1126 pos_ += sizeof(T);
1127 return value;
1128 }
1129
1131 [[nodiscard]] FormatType ReadFormatType() { return static_cast<FormatType>(*pos_++); }
1132
1142 [[nodiscard]] Spec ReadSpec()
1143 {
1144 return Spec{.flags = *pos_++,
1145 .fill = static_cast<char>(*pos_++),
1146 .width = *pos_++,
1147 .precision = *pos_++};
1148 }
1149
1151 [[nodiscard]] std::string_view ReadInlineText()
1152 {
1153 auto text = reinterpret_cast<const char*>(pos_);
1154 size_t size = std::strlen(text);
1155 pos_ += size + 1;
1156 return std::string_view(text, size);
1157 }
1158
1160 [[nodiscard]] std::string_view ReadTextRef()
1161 {
1162 auto offset = Read<uint16_t>();
1163 auto size = Read<uint16_t>();
1164 auto text = reinterpret_cast<const char*>(base_ + offset);
1165 return std::string_view(text, size);
1166 }
1167
1168 private:
1169 const uint8_t* pos_ = nullptr;
1170 const uint8_t* base_ = nullptr;
1171};
1172
1178{
1179 public:
1181 explicit ArgumentReader(const uint8_t* data) : pos_(data) {}
1182
1184 template <typename T>
1185 [[nodiscard]] T Read()
1186 {
1187 T value{};
1188 std::memcpy(&value, pos_, sizeof(T));
1189 pos_ += sizeof(T);
1190 return value;
1191 }
1192
1193 private:
1194 const uint8_t* pos_ = nullptr;
1195};
1196
1201template <OutputSink Sink, FormatProfile Profile>
1203{
1204 public:
1206 Executor(Sink& sink, const uint8_t* codes, const uint8_t* args)
1207 : sink_(sink),
1208 codes_(codes),
1209 args_(args)
1210 {
1211 }
1212
1214 [[nodiscard]] ErrorCode Run()
1215 {
1216 while (true)
1217 {
1218 auto op = codes_.ReadOp();
1219 if (op == FormatOp::End)
1220 {
1221 return ErrorCode::OK;
1222 }
1223
1224 auto ec = DispatchOp(op);
1225 if (ec != ErrorCode::OK)
1226 {
1227 return ec;
1228 }
1229 }
1230 }
1231
1232 private:
1233 // Raw sink and generic field-writing helpers.
1234 // 原始输出与通用字段写出辅助函数。
1235 [[nodiscard]] ErrorCode WriteRaw(std::string_view text) { return sink_.Write(text); }
1236 [[nodiscard]] ErrorCode WritePadding(char fill, size_t count)
1237 {
1238 char chunk[16];
1239 std::memset(chunk, fill, sizeof(chunk));
1240
1241 while (count != 0)
1242 {
1243 size_t step = (count < sizeof(chunk)) ? count : sizeof(chunk);
1244 auto ec = WriteRaw(std::string_view(chunk, step));
1245 if (ec != ErrorCode::OK)
1246 {
1247 return ec;
1248 }
1249 count -= step;
1250 }
1251
1252 return ErrorCode::OK;
1253 }
1254 [[nodiscard]] ErrorCode WriteTextField(std::string_view text, const Spec& spec)
1255 {
1256 size_t pad = FieldPadding(spec.width, text.size());
1257 size_t left_pad = 0;
1258 size_t right_pad = 0;
1259 if (spec.LeftAlign())
1260 {
1261 right_pad = pad;
1262 }
1263 else if (spec.CenterAlign())
1264 {
1265 left_pad = pad / 2;
1266 right_pad = pad - left_pad;
1267 }
1268 else
1269 {
1270 left_pad = pad;
1271 }
1272
1273 if (auto ec = WritePadding(spec.fill, left_pad); ec != ErrorCode::OK)
1274 {
1275 return ec;
1276 }
1277 if (auto ec = WriteRaw(text); ec != ErrorCode::OK)
1278 {
1279 return ec;
1280 }
1281 return WritePadding(spec.fill, right_pad);
1282 }
1283 [[nodiscard]] ErrorCode WriteIntegerField(char sign_char, std::string_view prefix,
1284 std::string_view digits,
1285 const Spec& spec)
1286 {
1287 auto write_char = [this](char ch) -> ErrorCode {
1288 if (ch == '\0')
1289 {
1290 return ErrorCode::OK;
1291 }
1292 return WriteRaw(std::string_view(&ch, 1));
1293 };
1294 auto write_text = [this](std::string_view text) -> ErrorCode {
1295 if (text.empty())
1296 {
1297 return ErrorCode::OK;
1298 }
1299 return WriteRaw(text);
1300 };
1301
1302 size_t zeros = IntegerPrecisionZeros(spec, digits.size());
1303 size_t total = digits.size() + zeros + prefix.size() +
1304 static_cast<size_t>(sign_char != '\0');
1305 size_t pad = FieldPadding(spec.width, total);
1306 bool zero_fill = spec.ZeroPad() && !spec.LeftAlign() && !spec.CenterAlign() &&
1307 !spec.HasPrecision();
1308 size_t left_pad = 0;
1309 size_t middle_zeros = zero_fill ? pad : 0;
1310 size_t right_pad = 0;
1311 if (!zero_fill)
1312 {
1313 if (spec.LeftAlign())
1314 {
1315 right_pad = pad;
1316 }
1317 else if (spec.CenterAlign())
1318 {
1319 left_pad = pad / 2;
1320 right_pad = pad - left_pad;
1321 }
1322 else
1323 {
1324 left_pad = pad;
1325 }
1326 }
1327
1328 if (auto ec = WritePadding(spec.fill, left_pad); ec != ErrorCode::OK)
1329 {
1330 return ec;
1331 }
1332 if (auto ec = write_char(sign_char); ec != ErrorCode::OK)
1333 {
1334 return ec;
1335 }
1336 if (auto ec = write_text(prefix); ec != ErrorCode::OK)
1337 {
1338 return ec;
1339 }
1340 if (auto ec = WritePadding('0', middle_zeros); ec != ErrorCode::OK)
1341 {
1342 return ec;
1343 }
1344 if (auto ec = WritePadding('0', zeros); ec != ErrorCode::OK)
1345 {
1346 return ec;
1347 }
1348 if (auto ec = write_text(digits); ec != ErrorCode::OK)
1349 {
1350 return ec;
1351 }
1352 return WritePadding(spec.fill, right_pad);
1353 }
1354 [[nodiscard]] ErrorCode WriteFloatField(char sign_char, std::string_view text,
1355 const Spec& spec)
1356 {
1357 auto write_char = [this](char ch) -> ErrorCode {
1358 if (ch == '\0')
1359 {
1360 return ErrorCode::OK;
1361 }
1362 return WriteRaw(std::string_view(&ch, 1));
1363 };
1364
1365 size_t total = text.size() + static_cast<size_t>(sign_char != '\0');
1366 size_t pad = FieldPadding(spec.width, total);
1367 bool zero_fill = spec.ZeroPad() && !spec.LeftAlign() && !spec.CenterAlign();
1368 size_t left_pad = 0;
1369 size_t middle_zeros = zero_fill ? pad : 0;
1370 size_t right_pad = 0;
1371 if (!zero_fill)
1372 {
1373 if (spec.LeftAlign())
1374 {
1375 right_pad = pad;
1376 }
1377 else if (spec.CenterAlign())
1378 {
1379 left_pad = pad / 2;
1380 right_pad = pad - left_pad;
1381 }
1382 else
1383 {
1384 left_pad = pad;
1385 }
1386 }
1387
1388 if (auto ec = WritePadding(spec.fill, left_pad); ec != ErrorCode::OK)
1389 {
1390 return ec;
1391 }
1392 if (auto ec = write_char(sign_char); ec != ErrorCode::OK)
1393 {
1394 return ec;
1395 }
1396 if (auto ec = WritePadding('0', middle_zeros); ec != ErrorCode::OK)
1397 {
1398 return ec;
1399 }
1400 if (auto ec = WriteRaw(text); ec != ErrorCode::OK)
1401 {
1402 return ec;
1403 }
1404 return WritePadding(spec.fill, right_pad);
1405 }
1406
1407 template <std::signed_integral Int>
1408 [[nodiscard]] static char ResolveSignChar(Int value, const Spec& spec)
1409 {
1410 if (value < 0)
1411 {
1412 return '-';
1413 }
1414 if (spec.ForceSign())
1415 {
1416 return '+';
1417 }
1418 if (spec.SpaceSign())
1419 {
1420 return ' ';
1421 }
1422 return '\0';
1423 }
1424
1425 template <typename T>
1426 [[nodiscard]] static char ResolveFloatSignChar(T value, const Spec& spec)
1427 {
1428 if (std::signbit(value))
1429 {
1430 return '-';
1431 }
1432 if (spec.ForceSign())
1433 {
1434 return '+';
1435 }
1436 if (spec.SpaceSign())
1437 {
1438 return ' ';
1439 }
1440 return '\0';
1441 }
1442
1443 template <std::signed_integral Int>
1444 [[nodiscard]] ErrorCode WriteSigned(const Spec& spec, Int value)
1445 {
1446 using UInt = std::make_unsigned_t<Int>;
1447 char digit_buffer[32];
1448 UInt bits = static_cast<UInt>(value);
1449 UInt magnitude = (value < 0) ? (UInt{0} - bits) : bits;
1450 size_t digit_count = AppendUnsigned(digit_buffer, magnitude, 10, false);
1451
1452 std::string_view digits(digit_buffer, digit_count);
1453 if (value == 0 && spec.precision == 0)
1454 {
1455 digits = {};
1456 }
1457
1458 return WriteIntegerField(ResolveSignChar(value, spec), {}, digits, spec);
1459 }
1460
1461 template <std::unsigned_integral UInt>
1462 [[nodiscard]] ErrorCode WriteUnsigned(FormatType type, const Spec& spec, UInt value)
1463 {
1464 uint8_t base = IntegerBase(type);
1465 if (base == 0)
1466 {
1467 return ErrorCode::ARG_ERR;
1468 }
1469
1470 bool upper_case = IntegerUpperCase(type);
1471 auto prefix = IntegerPrefix(type, spec, value);
1472
1473 char digit_buffer[33];
1474 size_t digit_count = AppendUnsigned(digit_buffer, value, base, upper_case);
1475
1476 if (type == FormatType::Octal32 || type == FormatType::Octal64)
1477 {
1478 digit_count = ApplyAlternateOctal(digit_buffer, digit_count, spec, value);
1479 }
1480 else if (value == 0 && spec.precision == 0)
1481 {
1482 digit_count = 0;
1483 }
1484
1485 std::string_view digits(digit_buffer, digit_count);
1486 return WriteIntegerField('\0', prefix, digits, spec);
1487 }
1488 [[nodiscard]] ErrorCode WritePointer(const Spec& spec, uintptr_t value)
1489 {
1490 char digit_buffer[2 * sizeof(uintptr_t)];
1491 size_t digit_count = AppendUnsigned(digit_buffer, value, 16, false);
1492 Spec actual = spec;
1493
1494 if (!actual.HasPrecision() || actual.precision == 0)
1495 {
1496 actual.precision = 1;
1497 }
1498
1499 return WriteIntegerField('\0', "0x", std::string_view(digit_buffer, digit_count),
1500 actual);
1501 }
1502 [[nodiscard]] ErrorCode WriteCharacter(const Spec& spec, char ch)
1503 {
1504 return WriteTextField(std::string_view(&ch, 1), spec);
1505 }
1506 [[nodiscard]] ErrorCode WriteString(const Spec& spec, std::string_view text)
1507 {
1508 auto view = text;
1509 if (spec.HasPrecision() && spec.precision < view.size())
1510 {
1511 view = view.substr(0, spec.precision);
1512 }
1513
1514 return WriteTextField(view, spec);
1515 }
1516
1517 template <typename T>
1518 [[nodiscard]] ErrorCode WriteFloat(FormatType type, const Spec& spec, T value)
1519 {
1520 if (!UsesFloatTextBackend(type))
1521 {
1522 return ErrorCode::ARG_ERR;
1523 }
1524
1525 char sign_char = ResolveFloatSignChar(value, spec);
1526 T magnitude = std::signbit(value) ? -static_cast<T>(value) : static_cast<T>(value);
1527 char output_buffer[float_buffer_capacity];
1528 size_t output_size = 0;
1529 if (!FormatFloatText(type, spec, magnitude, output_buffer, output_size))
1530 {
1531 return ErrorCode::NO_BUFF;
1532 }
1533
1534 return WriteFloatField(sign_char, std::string_view(output_buffer, output_size), spec);
1535 }
1536
1538 [[nodiscard]] ErrorCode WriteU32Dec(uint32_t value)
1539 {
1540 char digit_buffer[10];
1541 size_t digit_count = AppendUnsigned(digit_buffer, value, 10, false);
1542 return WriteRaw(std::string_view(digit_buffer, digit_count));
1543 }
1544
1546 [[nodiscard]] ErrorCode WriteU32ZeroPadWidth(uint8_t width, uint32_t value)
1547 {
1548 char digit_buffer[10];
1549 size_t digit_count = AppendUnsigned(digit_buffer, value, 10, false);
1550 size_t zeros = FieldPadding(width, digit_count);
1551 if (auto ec = WritePadding('0', zeros); ec != ErrorCode::OK)
1552 {
1553 return ec;
1554 }
1555 return WriteRaw(std::string_view(digit_buffer, digit_count));
1556 }
1557
1559 [[nodiscard]] ErrorCode WriteStringRaw(std::string_view text)
1560 {
1561 return WriteRaw(text);
1562 }
1563
1565 [[nodiscard]] ErrorCode WriteF32FixedPrec(uint8_t precision, float value)
1566 {
1567 char sign_char = std::signbit(value) ? '-' : '\0';
1568 float magnitude = std::signbit(value) ? -value : value;
1569 char output_buffer[float_buffer_capacity];
1570 size_t output_size = 0;
1571 if (!FormatF32FixedPrecText(magnitude, precision, output_buffer, output_size))
1572 {
1573 return ErrorCode::NO_BUFF;
1574 }
1575
1576 if (sign_char != '\0')
1577 {
1578 if (auto ec = WriteRaw(std::string_view(&sign_char, 1)); ec != ErrorCode::OK)
1579 {
1580 return ec;
1581 }
1582 }
1583
1584 return WriteRaw(std::string_view(output_buffer, output_size));
1585 }
1586
1588 [[nodiscard]] ErrorCode WriteF64FixedPrec(uint8_t precision, double value)
1589 {
1590 return WriteFloat(FormatType::DoubleFixed, Spec{.precision = precision}, value);
1591 }
1592
1593 // Small bridges that keep GenericField dispatch readable while preserving the
1594 // existing "read spec -> read next packed argument -> call concrete writer"
1595 // execution order.
1596 // 这些小桥接函数只负责让 GenericField 分发更易读,同时保持原有的
1597 // “读 spec -> 读下一个已打包参数 -> 调具体 writer” 执行顺序不变。
1598 template <std::signed_integral Int>
1599 [[nodiscard]] ErrorCode DispatchSignedField()
1600 {
1601 return WriteSigned(codes_.ReadSpec(), args_.Read<Int>());
1602 }
1603
1604 template <FormatType Type, std::unsigned_integral UInt>
1605 [[nodiscard]] ErrorCode DispatchUnsignedField()
1606 {
1607 return WriteUnsigned(Type, codes_.ReadSpec(), args_.Read<UInt>());
1608 }
1609
1610 template <FormatType Type, typename Float>
1611 [[nodiscard]] ErrorCode DispatchFloatField()
1612 {
1613 return WriteFloat(Type, codes_.ReadSpec(), args_.Read<Float>());
1614 }
1615
1616 [[nodiscard]] ErrorCode DispatchPointerField()
1617 {
1618 return WritePointer(codes_.ReadSpec(), args_.Read<uintptr_t>());
1619 }
1620
1621 [[nodiscard]] ErrorCode DispatchCharacterField()
1622 {
1623 return WriteCharacter(codes_.ReadSpec(), args_.Read<char>());
1624 }
1625
1626 [[nodiscard]] ErrorCode DispatchStringField()
1627 {
1628 return WriteString(codes_.ReadSpec(), args_.Read<std::string_view>());
1629 }
1630
1632 [[nodiscard]] ErrorCode DispatchGenericField(FormatType type)
1633 {
1634 switch (type)
1635 {
1636 case FormatType::Signed32:
1637 if constexpr (!Config::enable_integer)
1638 {
1639 return ErrorCode::STATE_ERR;
1640 }
1641 return DispatchSignedField<int32_t>();
1642 case FormatType::Signed64:
1643 if constexpr (!Config::enable_integer || !Config::enable_integer_64bit)
1644 {
1645 return ErrorCode::STATE_ERR;
1646 }
1647 return DispatchSignedField<int64_t>();
1648 case FormatType::Unsigned32:
1649 if constexpr (!Config::enable_integer)
1650 {
1651 return ErrorCode::STATE_ERR;
1652 }
1653 return DispatchUnsignedField<FormatType::Unsigned32, uint32_t>();
1654 case FormatType::Unsigned64:
1655 if constexpr (!Config::enable_integer || !Config::enable_integer_64bit)
1656 {
1657 return ErrorCode::STATE_ERR;
1658 }
1659 return DispatchUnsignedField<FormatType::Unsigned64, uint64_t>();
1660 case FormatType::Binary32:
1661 if constexpr (!Config::enable_integer || !Config::enable_integer_base8_16)
1662 {
1663 return ErrorCode::STATE_ERR;
1664 }
1665 return DispatchUnsignedField<FormatType::Binary32, uint32_t>();
1666 case FormatType::Binary64:
1667 if constexpr (!Config::enable_integer || !Config::enable_integer_base8_16 ||
1668 !Config::enable_integer_64bit)
1669 {
1670 return ErrorCode::STATE_ERR;
1671 }
1672 return DispatchUnsignedField<FormatType::Binary64, uint64_t>();
1673 case FormatType::Octal32:
1674 if constexpr (!Config::enable_integer || !Config::enable_integer_base8_16)
1675 {
1676 return ErrorCode::STATE_ERR;
1677 }
1678 return DispatchUnsignedField<FormatType::Octal32, uint32_t>();
1679 case FormatType::Octal64:
1680 if constexpr (!Config::enable_integer || !Config::enable_integer_base8_16 ||
1681 !Config::enable_integer_64bit)
1682 {
1683 return ErrorCode::STATE_ERR;
1684 }
1685 return DispatchUnsignedField<FormatType::Octal64, uint64_t>();
1686 case FormatType::HexLower32:
1687 if constexpr (!Config::enable_integer || !Config::enable_integer_base8_16)
1688 {
1689 return ErrorCode::STATE_ERR;
1690 }
1691 return DispatchUnsignedField<FormatType::HexLower32, uint32_t>();
1692 case FormatType::HexLower64:
1693 if constexpr (!Config::enable_integer || !Config::enable_integer_base8_16 ||
1694 !Config::enable_integer_64bit)
1695 {
1696 return ErrorCode::STATE_ERR;
1697 }
1698 return DispatchUnsignedField<FormatType::HexLower64, uint64_t>();
1699 case FormatType::HexUpper32:
1700 if constexpr (!Config::enable_integer || !Config::enable_integer_base8_16)
1701 {
1702 return ErrorCode::STATE_ERR;
1703 }
1704 return DispatchUnsignedField<FormatType::HexUpper32, uint32_t>();
1705 case FormatType::HexUpper64:
1706 if constexpr (!Config::enable_integer || !Config::enable_integer_base8_16 ||
1707 !Config::enable_integer_64bit)
1708 {
1709 return ErrorCode::STATE_ERR;
1710 }
1711 return DispatchUnsignedField<FormatType::HexUpper64, uint64_t>();
1712 case FormatType::Pointer:
1713 if constexpr (!Config::enable_pointer)
1714 {
1715 return ErrorCode::STATE_ERR;
1716 }
1717 return DispatchPointerField();
1718 case FormatType::Character:
1719 if constexpr (!Config::enable_text)
1720 {
1721 return ErrorCode::STATE_ERR;
1722 }
1723 return DispatchCharacterField();
1724 case FormatType::String:
1725 if constexpr (!Config::enable_text)
1726 {
1727 return ErrorCode::STATE_ERR;
1728 }
1729 return DispatchStringField();
1730 case FormatType::FloatFixed:
1731 if constexpr (!FloatEnabled(FormatType::FloatFixed))
1732 {
1733 return ErrorCode::STATE_ERR;
1734 }
1735 return DispatchFloatField<FormatType::FloatFixed, float>();
1736 case FormatType::DoubleFixed:
1737 if constexpr (!FloatEnabled(FormatType::DoubleFixed))
1738 {
1739 return ErrorCode::STATE_ERR;
1740 }
1741 return DispatchFloatField<FormatType::DoubleFixed, double>();
1742 case FormatType::FloatScientific:
1743 if constexpr (!FloatEnabled(FormatType::FloatScientific))
1744 {
1745 return ErrorCode::STATE_ERR;
1746 }
1747 return DispatchFloatField<FormatType::FloatScientific, float>();
1748 case FormatType::DoubleScientific:
1749 if constexpr (!FloatEnabled(FormatType::DoubleScientific))
1750 {
1751 return ErrorCode::STATE_ERR;
1752 }
1753 return DispatchFloatField<FormatType::DoubleScientific, double>();
1754 case FormatType::FloatGeneral:
1755 if constexpr (!FloatEnabled(FormatType::FloatGeneral))
1756 {
1757 return ErrorCode::STATE_ERR;
1758 }
1759 return DispatchFloatField<FormatType::FloatGeneral, float>();
1760 case FormatType::DoubleGeneral:
1761 if constexpr (!FloatEnabled(FormatType::DoubleGeneral))
1762 {
1763 return ErrorCode::STATE_ERR;
1764 }
1765 return DispatchFloatField<FormatType::DoubleGeneral, double>();
1766 case FormatType::LongDoubleFixed:
1767 if constexpr (!FloatEnabled(FormatType::LongDoubleFixed))
1768 {
1769 return ErrorCode::STATE_ERR;
1770 }
1771 return DispatchFloatField<FormatType::LongDoubleFixed, long double>();
1772 case FormatType::LongDoubleScientific:
1773 if constexpr (!FloatEnabled(FormatType::LongDoubleScientific))
1774 {
1775 return ErrorCode::STATE_ERR;
1776 }
1777 return DispatchFloatField<FormatType::LongDoubleScientific, long double>();
1778 case FormatType::LongDoubleGeneral:
1779 if constexpr (!FloatEnabled(FormatType::LongDoubleGeneral))
1780 {
1781 return ErrorCode::STATE_ERR;
1782 }
1783 return DispatchFloatField<FormatType::LongDoubleGeneral, long double>();
1784 case FormatType::TextInline:
1785 case FormatType::TextRef:
1786 case FormatType::TextSpace:
1787 case FormatType::End:
1788 default:
1789 return ErrorCode::STATE_ERR;
1790 }
1791 }
1792
1794 [[nodiscard]] ErrorCode DispatchOp(FormatOp op)
1795 {
1796 switch (op)
1797 {
1798 case FormatOp::TextInline:
1799 return WriteRaw(codes_.ReadInlineText());
1800 case FormatOp::TextRef:
1801 return WriteRaw(codes_.ReadTextRef());
1802 case FormatOp::TextSpace:
1803 return WriteRaw(" ");
1804 case FormatOp::U32Dec:
1805 if constexpr (!HasProfile(Profile, FormatProfile::U32) ||
1806 !Config::enable_integer)
1807 {
1808 return ErrorCode::STATE_ERR;
1809 }
1810 return WriteU32Dec(args_.Read<uint32_t>());
1811 case FormatOp::U32ZeroPadWidth:
1812 if constexpr (!HasProfile(Profile, FormatProfile::U32) ||
1813 !Config::enable_integer)
1814 {
1815 return ErrorCode::STATE_ERR;
1816 }
1817 return WriteU32ZeroPadWidth(codes_.Read<uint8_t>(), args_.Read<uint32_t>());
1818 case FormatOp::StringRaw:
1819 if constexpr (!HasProfile(Profile, FormatProfile::TextArg) ||
1820 !Config::enable_text)
1821 {
1822 return ErrorCode::STATE_ERR;
1823 }
1824 return WriteStringRaw(args_.Read<std::string_view>());
1825 case FormatOp::F32FixedPrec:
1826 if constexpr (!HasProfile(Profile, FormatProfile::F32Fixed) ||
1827 !FloatEnabled(FormatType::FloatFixed))
1828 {
1829 return ErrorCode::STATE_ERR;
1830 }
1831 return WriteF32FixedPrec(codes_.Read<uint8_t>(), args_.Read<float>());
1832 case FormatOp::F64FixedPrec:
1833 if constexpr (!HasProfile(Profile, FormatProfile::F64Fixed) ||
1834 !FloatEnabled(FormatType::DoubleFixed))
1835 {
1836 return ErrorCode::STATE_ERR;
1837 }
1838 return WriteF64FixedPrec(codes_.Read<uint8_t>(), args_.Read<double>());
1839 case FormatOp::GenericField:
1840 if constexpr (!HasProfile(Profile, FormatProfile::Generic))
1841 {
1842 return ErrorCode::STATE_ERR;
1843 }
1844 return DispatchGenericField(codes_.ReadFormatType());
1845 case FormatOp::End:
1846 default:
1847 return ErrorCode::STATE_ERR;
1848 }
1849 }
1850
1851 Sink& sink_;
1852 CodeReader codes_;
1853 ArgumentReader args_;
1854};
1855} // namespace LibXR::Print
Sequential reader for the packed runtime argument byte blob.
Definition writer.hpp:1178
T Read()
Reads one packed argument value without requiring alignment. / 以无对齐要求的方式读取一个已打包参数值
Definition writer.hpp:1185
ArgumentReader(const uint8_t *data)
Creates a reader over one packed runtime argument blob. / 从单个运行期参数打包字节块构造读取器
Definition writer.hpp:1181
Sequential reader for the compiled record stream.
Definition writer.hpp:1110
FormatOp ReadOp()
Reads the next runtime opcode. / 读取下一条运行期操作码
Definition writer.hpp:1118
std::string_view ReadTextRef()
Reads an offset/size pair pointing into the trailing text pool. The offset is already rebased against...
Definition writer.hpp:1160
FormatType ReadFormatType()
Reads the semantic type byte carried by one GenericField payload. / 读取 GenericField 载荷中的语义类型字节
Definition writer.hpp:1131
CodeReader(const uint8_t *codes)
Creates a reader over the beginning of one compiled byte blob. / 从单个编译字节块起点构造读取器
Definition writer.hpp:1113
T Read()
Reads a native-endian POD value emitted by the compile-time emitter. / 读取编译期发射器按本机字节序写入的 POD 值
Definition writer.hpp:1122
Spec ReadSpec()
Reads the 4-byte field payload that follows one GenericField type byte.
Definition writer.hpp:1142
std::string_view ReadInlineText()
Reads a null-terminated short text payload embedded in the record stream. / 读取内嵌在记录流中的短文本
Definition writer.hpp:1151
Per-sink bytecode executor specialized by the compiled format profile.
Definition writer.hpp:1203
Executor(Sink &sink, const uint8_t *codes, const uint8_t *args)
Binds one sink with one compiled byte blob and one packed argument blob. / 将一个输出端、一份编译字节块和一份参数字节块绑定起来
Definition writer.hpp:1206
ErrorCode WriteF64FixedPrec(uint8_t precision, double value)
Fast path for one fixed double with explicit precision. / 单个带显式精度的定点 double 快路径
Definition writer.hpp:1588
ErrorCode WriteF32FixedPrec(uint8_t precision, float value)
Fast path for one fixed float with explicit precision. / 单个带显式精度的定点 float 快路径
Definition writer.hpp:1565
ErrorCode DispatchOp(FormatOp op)
Dispatches one runtime opcode to the selected specialized path. / 将一个运行期操作码分发到选中的特化路径
Definition writer.hpp:1794
ErrorCode Run()
Runs until the compiled record stream reaches FormatOp::End. / 持续执行记录流,直到遇到 FormatOp::End.
Definition writer.hpp:1214
ErrorCode WriteStringRaw(std::string_view text)
Fast path for one raw string argument. / 单个原始字符串参数的快路径
Definition writer.hpp:1559
ErrorCode WriteU32ZeroPadWidth(uint8_t width, uint32_t value)
Fast path for one zero-padded uint32_t decimal field. / 单个零填充 uint32_t 十进制字段的快路径
Definition writer.hpp:1546
ErrorCode WriteU32Dec(uint32_t value)
Fast path for one raw uint32_t decimal field. / 单个原始 uint32_t 十进制字段的快路径
Definition writer.hpp:1538
ErrorCode DispatchGenericField(FormatType type)
Dispatches one GenericField payload to the corresponding wide fallback. / 将一个 GenericField 载荷分发到对应的宽回...
Definition writer.hpp:1632
Runtime backend that packs arguments and executes compiled format records.
Definition writer.hpp:29
static constexpr std::array< uint32_t, 10 > f32_decimal_scales_u32
Decimal scales used by the narrow float32 fixed-precision fast path. / 窄 float32 定点快路径使用的十进制缩放表
Definition writer.hpp:70
static constexpr float f32_u32_overflow_limit
Largest finite float32 value whose integer part still fits in uint32_t. / 整数部分仍可放入 uint32_t 的最大 float...
Definition writer.hpp:68
static bool AppendBufferU32ZeroPad(char *buffer, size_t capacity, size_t &size, uint32_t value, uint8_t width)
Appends one uint32_t decimal value and pads leading zeros up to width. / 追加一个 uint32_t 十进制值,并在前面补零到目标...
Definition writer.hpp:533
static constexpr uint8_t IntegerBase(FormatType type)
Returns the integer radix selected by one unsigned runtime type. / 返回某个无符号运行期类型对应的整数进制
Definition writer.hpp:362
static constexpr bool HasFlag(uint8_t flags, uint8_t bit)
Tests whether one decoded field-spec bit is set.
Definition writer.hpp:87
static constexpr size_t FieldPadding(uint8_t width, size_t payload_size)
Returns the padding width needed to expand one payload to the requested field width....
Definition writer.hpp:347
static ErrorCode RunArgumentOrder(Sink &sink, const Format &, Args &&... args)
Runs one compiled format whose runtime pack order is provided separately from the call-site argument ...
Definition writer.hpp:44
static constexpr auto PackValue(T &&value)
Normalizes one matched C++ argument into the packed runtime storage kind required by one compiled arg...
Definition writer.hpp:183
static uint8_t ExtractDigit(Float &value, Float scale)
Extracts one base-10 digit at the current scale while tolerating tiny FP residue. / 在当前十进制权重下提取一位数字,并...
Definition writer.hpp:660
static constexpr bool UsesFloatTextBackend(FormatType type)
Returns whether one runtime type is handled by the shared float text backend. / 判断某个运行期类型是否由共享浮点文本后端处...
Definition writer.hpp:460
static bool AppendBufferText(char *buffer, size_t capacity, size_t &size, std::string_view text)
Appends one text span to a bounded local formatting buffer. / 向有界本地格式化缓冲区追加一段文本
Definition writer.hpp:520
static DecimalScale< Float > NormalizeDecimal(Float value)
Normalizes one finite positive value so that value divided by scale stays in [1, 10)....
Definition writer.hpp:625
static constexpr bool IntegerUpperCase(FormatType type)
Returns whether one unsigned runtime type should emit uppercase hex digits. / 判断某个无符号运行期类型是否应输出大写十六进制...
Definition writer.hpp:386
static constexpr bool FloatEnabled(FormatType type)
Returns whether one runtime float type is currently enabled by feature switches. / 判断某个运行期浮点类型是否被当前功能...
Definition writer.hpp:480
static constexpr size_t IntegerPrecisionZeros(const Spec &spec, size_t digit_count)
Returns the extra leading-zero count introduced by integer precision. / 返回整数精度引入的额外前导零个数
Definition writer.hpp:353
static constexpr std::string_view IntegerPrefix(FormatType type, const Spec &spec, UInt value)
Returns the alternate-form prefix carried outside the digit payload. / 返回放在数字载荷之外的备用格式前缀
Definition writer.hpp:393
static size_t TrimGeneralText(char *text, size_t size)
Trims trailing zeros for general float output and removes a dangling decimal point when alternate for...
Definition writer.hpp:684
static bool AppendBufferChar(char *buffer, size_t capacity, size_t &size, char ch)
Appends one character to a bounded local formatting buffer. / 向有界本地格式化缓冲区追加一个字符
Definition writer.hpp:508
static uint64_t RoundScaledF32(float value, uint32_t scale)
Returns round(value * scale) using the exact float32 bit pattern and nearest-even ties....
Definition writer.hpp:553
static constexpr uint8_t unspecified_precision
Emits the stack argument byte blob for one compiled argument list.
Definition writer.hpp:63
static bool FormatF32FixedPrecText(float value, uint8_t precision, char *out, size_t &out_size)
Fixed-only float32 formatter that uses a uint32_t scaled-fraction fast path when possible....
Definition writer.hpp:716
static size_t ApplyAlternateOctal(char *digits, size_t digit_count, const Spec &spec, UInt value)
Applies %#o special rules directly onto the generated digit payload.
Definition writer.hpp:427
Writer 可执行的编译后格式对象。
接收编译格式输出的写入端。
ErrorCode
定义错误码枚举
@ STATE_ERR
状态错误 | State error
@ NO_BUFF
缓冲区不足 | Insufficient buffer
@ OK
操作成功 | Operation successful
@ ARG_ERR
参数错误 | Argument error
Internal C++ argument-type utilities shared by compile-time matching and runtime packing.
Float scale
10 ^ exponent / 10 的 exponent 次幂
Definition writer.hpp:588
int exponent
decimal exponent / 十进制指数
Definition writer.hpp:587
Runtime view of one decoded field specification byte group.
Definition writer.hpp:97
uint8_t width
field width, or zero when absent / 字段宽度,未指定时为 0
Definition writer.hpp:100
char fill
field fill character / 字段填充字符
Definition writer.hpp:99
uint8_t flags
FormatFlag bitset / 字段修饰位集合
Definition writer.hpp:98
uint8_t precision
precision, or unspecified_precision / 字段精度,未指定时为哨兵值
Definition writer.hpp:101