libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
LibXR::Print::Writer Class Reference

Runtime backend that packs arguments and executes compiled format records. More...

#include <writer.hpp>

Data Structures

class  ArgumentReader
 Sequential reader for the packed runtime argument byte blob. More...
 
class  CodeReader
 Sequential reader for the compiled record stream. More...
 
struct  DecimalScale
 
class  Executor
 Per-sink bytecode executor specialized by the compiled format profile. More...
 
struct  Spec
 Runtime view of one decoded field specification byte group. More...
 

Static Public Member Functions

template<typename Sink , typename Format , auto ArgumentOrder, typename... Args>
requires OutputSink<Sink> && CompiledFormat<std::remove_cvref_t<Format>>
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 order.
 

Private Member Functions

template<OutputSink Sink, FormatProfile Profile>
 __attribute__ ((noinline)) static ErrorCode Execute(Sink &sink
 
template<OutputSink Sink, auto ArgumentInfoList, auto ArgumentOrder, FormatProfile Profile, typename... Args>
 __attribute__ ((noinline)) static ErrorCode RunTaggedArgumentOrder(Sink &sink
 

Static Private Member Functions

static constexpr bool HasFlag (uint8_t flags, uint8_t bit)
 Tests whether one decoded field-spec bit is set.
 
template<typename T >
static constexpr std::string_view ToStringView (const T &text)
 
template<FormatPackKind pack, typename T >
static constexpr auto PackValue (T &&value)
 Normalizes one matched C++ argument into the packed runtime storage kind required by one compiled argument slot.
 
template<typename T >
static void StoreArgument (uint8_t *&out, const T &value)
 
template<auto ArgumentInfoList>
static consteval size_t PackedArgumentBytes ()
 
template<auto ArgumentInfoList, auto ArgumentOrder, typename Tuple >
static void StoreArgumentsOrdered (uint8_t *&out, Tuple &tuple)
 
template<std::unsigned_integral UInt>
static size_t AppendUnsigned (char *out, UInt value, uint8_t base, bool upper_case)
 
static size_t AppendSmallUnsigned (char *out, uint8_t value)
 
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. / 返回把某段载荷扩展到目标字段宽度所需的填充长度
 
static constexpr size_t IntegerPrecisionZeros (const Spec &spec, size_t digit_count)
 Returns the extra leading-zero count introduced by integer precision. / 返回整数精度引入的额外前导零个数
 
static constexpr uint8_t IntegerBase (FormatType type)
 Returns the integer radix selected by one unsigned runtime type. / 返回某个无符号运行期类型对应的整数进制
 
static constexpr bool IntegerUpperCase (FormatType type)
 Returns whether one unsigned runtime type should emit uppercase hex digits. / 判断某个无符号运行期类型是否应输出大写十六进制数字
 
template<std::unsigned_integral UInt>
static constexpr std::string_view IntegerPrefix (FormatType type, const Spec &spec, UInt value)
 Returns the alternate-form prefix carried outside the digit payload. / 返回放在数字载荷之外的备用格式前缀
 
template<std::unsigned_integral UInt>
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.
 
static constexpr bool UsesFloatTextBackend (FormatType type)
 Returns whether one runtime type is handled by the shared float text backend. / 判断某个运行期类型是否由共享浮点文本后端处理
 
static constexpr bool FloatEnabled (FormatType type)
 Returns whether one runtime float type is currently enabled by feature switches. / 判断某个运行期浮点类型是否被当前功能开关启用
 
static bool AppendBufferChar (char *buffer, size_t capacity, size_t &size, char ch)
 Appends one character to a bounded local formatting buffer. / 向有界本地格式化缓冲区追加一个字符
 
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. / 向有界本地格式化缓冲区追加一段文本
 
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 十进制值,并在前面补零到目标宽度
 
static uint64_t RoundScaledF32 (float value, uint32_t scale)
 Returns round(value * scale) using the exact float32 bit pattern and nearest-even ties. / 基于精确 float32 位模式并按最近偶数处理平局返回 round(value * scale)
 
template<typename Float >
static Float Power10 (int exponent)
 
template<typename Float >
static DecimalScale< Float > NormalizeDecimal (Float value)
 Normalizes one finite positive value so that value divided by scale stays in [1, 10). / 将一个有限正值规范化,使 value 除以 scale 后落在 [1, 10)
 
template<typename Float >
static uint8_t ExtractDigit (Float &value, Float scale)
 Extracts one base-10 digit at the current scale while tolerating tiny FP residue. / 在当前十进制权重下提取一位数字,并容忍微小浮点残差
 
static size_t TrimGeneralText (char *text, size_t size)
 Trims trailing zeros for general float output and removes a dangling decimal point when alternate form is absent. / 在未启用备用格式时修剪通用浮点输出的尾随零,并去掉孤立小数点
 
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. / 仅供 float32 定点输出使用的格式化器,在可行时优先走 uint32_t 缩放小数快路径
 
template<typename Float >
static bool FormatFixedText (Float value, uint8_t precision, bool alternate, char *out, size_t &out_size)
 
static bool AppendExponentText (char *out, size_t &out_size, int exponent, bool upper_case)
 
template<typename Float >
static bool FormatScientificText (Float value, uint8_t precision, bool alternate, bool upper_case, char *out, size_t &out_size)
 
template<typename Float >
static bool FormatFloatText (FormatType type, const Spec &spec, Float value, char *out, size_t &out_size)
 

Private Attributes

const uint8_t * codes
 
const uint8_t const uint8_t * args
 

Static Private Attributes

static constexpr uint8_t unspecified_precision = 0xFF
 Emits the stack argument byte blob for one compiled argument list.
 
static constexpr size_t float_buffer_capacity = 512
 
template<FormatPackKind K>
static constexpr bool dependent_false_v = false
 
static constexpr float f32_u32_overflow_limit = 4294967296.0f
 Largest finite float32 value whose integer part still fits in uint32_t. / 整数部分仍可放入 uint32_t 的最大 float32 值上界
 
static constexpr std::array< uint32_t, 10 > f32_decimal_scales_u32
 Decimal scales used by the narrow float32 fixed-precision fast path. / 窄 float32 定点快路径使用的十进制缩放表
 

Detailed Description

Runtime backend that packs arguments and executes compiled format records.

运行期后端,负责打包参数并执行编译后的格式记录。

Definition at line 28 of file writer.hpp.

Member Function Documentation

◆ AppendBufferChar()

static bool LibXR::Print::Writer::AppendBufferChar ( char * buffer,
size_t capacity,
size_t & size,
char ch )
inlinestaticnodiscardprivate

Appends one character to a bounded local formatting buffer. / 向有界本地格式化缓冲区追加一个字符

Definition at line 508 of file writer.hpp.

510 {
511 if (size >= capacity)
512 {
513 return false;
514 }
515 buffer[size++] = ch;
516 return true;
517 }

◆ AppendBufferText()

static bool LibXR::Print::Writer::AppendBufferText ( char * buffer,
size_t capacity,
size_t & size,
std::string_view text )
inlinestaticnodiscardprivate

Appends one text span to a bounded local formatting buffer. / 向有界本地格式化缓冲区追加一段文本

Definition at line 520 of file writer.hpp.

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 }

◆ AppendBufferU32ZeroPad()

static bool LibXR::Print::Writer::AppendBufferU32ZeroPad ( char * buffer,
size_t capacity,
size_t & size,
uint32_t value,
uint8_t width )
inlinestaticnodiscardprivate

Appends one uint32_t decimal value and pads leading zeros up to width. / 追加一个 uint32_t 十进制值,并在前面补零到目标宽度

Definition at line 533 of file writer.hpp.

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 }
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 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

◆ AppendExponentText()

static bool LibXR::Print::Writer::AppendExponentText ( char * out,
size_t & out_size,
int exponent,
bool upper_case )
inlinestaticnodiscardprivate

Definition at line 929 of file writer.hpp.

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 }

◆ AppendSmallUnsigned()

static size_t LibXR::Print::Writer::AppendSmallUnsigned ( char * out,
uint8_t value )
inlinestaticnodiscardprivate

Definition at line 341 of file writer.hpp.

342 {
343 return AppendUnsigned(out, value, 10, false);
344 }

◆ AppendUnsigned()

template<std::unsigned_integral UInt>
static size_t LibXR::Print::Writer::AppendUnsigned ( char * out,
UInt value,
uint8_t base,
bool upper_case )
inlinestaticnodiscardprivate

Definition at line 312 of file writer.hpp.

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 }

◆ ApplyAlternateOctal()

template<std::unsigned_integral UInt>
static size_t LibXR::Print::Writer::ApplyAlternateOctal ( char * digits,
size_t digit_count,
const Spec & spec,
UInt value )
inlinestaticnodiscardprivate

Applies %#o special rules directly onto the generated digit payload.

直接在已生成的数字载荷上应用 %#o 的特殊规则。

Octal alternate form differs from hex: it is represented by a leading zero in the digit payload itself, not by a detached prefix string. This helper also preserves the required single 0 when %#.0o formats zero. 八进制备用格式与十六进制不同:它通过数字载荷本体前导一个 0 来表示, 而不是额外分离出的前缀字符串。本函数也负责在 %#.0o 格式化零值时保留 必需的单个 0。

Definition at line 427 of file writer.hpp.

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 }

◆ ExtractDigit()

template<typename Float >
static uint8_t LibXR::Print::Writer::ExtractDigit ( Float & value,
Float scale )
inlinestaticnodiscardprivate

Extracts one base-10 digit at the current scale while tolerating tiny FP residue. / 在当前十进制权重下提取一位数字,并容忍微小浮点残差

Definition at line 660 of file writer.hpp.

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 }

◆ FieldPadding()

static constexpr size_t LibXR::Print::Writer::FieldPadding ( uint8_t width,
size_t payload_size )
inlinestaticnodiscardconstexprprivate

Returns the padding width needed to expand one payload to the requested field width. / 返回把某段载荷扩展到目标字段宽度所需的填充长度

Definition at line 347 of file writer.hpp.

348 {
349 return (width > payload_size) ? static_cast<size_t>(width) - payload_size : 0;
350 }

◆ FloatEnabled()

static constexpr bool LibXR::Print::Writer::FloatEnabled ( FormatType type)
inlinestaticnodiscardconstexprprivate

Returns whether one runtime float type is currently enabled by feature switches. / 判断某个运行期浮点类型是否被当前功能开关启用

Definition at line 480 of file writer.hpp.

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 }

◆ FormatF32FixedPrecText()

static bool LibXR::Print::Writer::FormatF32FixedPrecText ( float value,
uint8_t precision,
char * out,
size_t & out_size )
inlinestaticnodiscardprivate

Fixed-only float32 formatter that uses a uint32_t scaled-fraction fast path when possible. / 仅供 float32 定点输出使用的格式化器,在可行时优先走 uint32_t 缩放小数快路径

Definition at line 716 of file writer.hpp.

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 }
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 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

◆ FormatFixedText()

template<typename Float >
static bool LibXR::Print::Writer::FormatFixedText ( Float value,
uint8_t precision,
bool alternate,
char * out,
size_t & out_size )
inlinestaticnodiscardprivate

Definition at line 887 of file writer.hpp.

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 }
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 DecimalScale< Float > NormalizeDecimal(Float value)
Normalizes one finite positive value so that value divided by scale stays in [1, 10)....
Definition writer.hpp:625

◆ FormatFloatText()

template<typename Float >
static bool LibXR::Print::Writer::FormatFloatText ( FormatType type,
const Spec & spec,
Float value,
char * out,
size_t & out_size )
inlinestaticnodiscardprivate

Definition at line 1004 of file writer.hpp.

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 }

◆ FormatScientificText()

template<typename Float >
static bool LibXR::Print::Writer::FormatScientificText ( Float value,
uint8_t precision,
bool alternate,
bool upper_case,
char * out,
size_t & out_size )
inlinestaticnodiscardprivate

Definition at line 958 of file writer.hpp.

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 }

◆ HasFlag()

static constexpr bool LibXR::Print::Writer::HasFlag ( uint8_t flags,
uint8_t bit )
inlinestaticnodiscardconstexprprivate

Tests whether one decoded field-spec bit is set.

判断某个已解码字段修饰位是否被设置。

Definition at line 87 of file writer.hpp.

88 {
89 return (flags & bit) != 0;
90 }

◆ IntegerBase()

static constexpr uint8_t LibXR::Print::Writer::IntegerBase ( FormatType type)
inlinestaticnodiscardconstexprprivate

Returns the integer radix selected by one unsigned runtime type. / 返回某个无符号运行期类型对应的整数进制

Definition at line 362 of file writer.hpp.

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 }

◆ IntegerPrecisionZeros()

static constexpr size_t LibXR::Print::Writer::IntegerPrecisionZeros ( const Spec & spec,
size_t digit_count )
inlinestaticnodiscardconstexprprivate

Returns the extra leading-zero count introduced by integer precision. / 返回整数精度引入的额外前导零个数

Definition at line 353 of file writer.hpp.

355 {
356 return (spec.HasPrecision() && spec.precision > digit_count)
357 ? static_cast<size_t>(spec.precision) - digit_count
358 : 0;
359 }

◆ IntegerPrefix()

template<std::unsigned_integral UInt>
static constexpr std::string_view LibXR::Print::Writer::IntegerPrefix ( FormatType type,
const Spec & spec,
UInt value )
inlinestaticnodiscardconstexprprivate

Returns the alternate-form prefix carried outside the digit payload. / 返回放在数字载荷之外的备用格式前缀

Definition at line 393 of file writer.hpp.

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 }

◆ IntegerUpperCase()

static constexpr bool LibXR::Print::Writer::IntegerUpperCase ( FormatType type)
inlinestaticnodiscardconstexprprivate

Returns whether one unsigned runtime type should emit uppercase hex digits. / 判断某个无符号运行期类型是否应输出大写十六进制数字

Definition at line 386 of file writer.hpp.

387 {
388 return type == FormatType::HexUpper32 || type == FormatType::HexUpper64;
389 }

◆ NormalizeDecimal()

template<typename Float >
static DecimalScale< Float > LibXR::Print::Writer::NormalizeDecimal ( Float value)
inlinestaticnodiscardprivate

Normalizes one finite positive value so that value divided by scale stays in [1, 10). / 将一个有限正值规范化,使 value 除以 scale 后落在 [1, 10)

Definition at line 625 of file writer.hpp.

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 }

◆ PackedArgumentBytes()

template<auto ArgumentInfoList>
static consteval size_t LibXR::Print::Writer::PackedArgumentBytes ( )
inlinestaticnodiscardconstevalprivate

Definition at line 291 of file writer.hpp.

292 {
293 size_t bytes = 0;
294 for (const auto& argument : ArgumentInfoList)
295 {
296 bytes += FormatArgumentBytes(argument.pack);
297 }
298 return bytes;
299 }

◆ PackValue()

template<FormatPackKind pack, typename T >
static constexpr auto LibXR::Print::Writer::PackValue ( T && value)
inlinestaticnodiscardconstexprprivate

Normalizes one matched C++ argument into the packed runtime storage kind required by one compiled argument slot.

将一个已匹配的 C++ 实参归一化为某个编译参数槽要求的运行期打包存储类型。

Definition at line 183 of file writer.hpp.

184 {
185 using Traits = Detail::FormatArgument::TypeTraits<T>;
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 }

◆ Power10()

template<typename Float >
static Float LibXR::Print::Writer::Power10 ( int exponent)
inlinestaticnodiscardprivate

Definition at line 592 of file writer.hpp.

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 }

◆ RoundScaledF32()

static uint64_t LibXR::Print::Writer::RoundScaledF32 ( float value,
uint32_t scale )
inlinestaticnodiscardprivate

Returns round(value * scale) using the exact float32 bit pattern and nearest-even ties. / 基于精确 float32 位模式并按最近偶数处理平局返回 round(value * scale)

Definition at line 553 of file writer.hpp.

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 }

◆ RunArgumentOrder()

template<typename Sink , typename Format , auto ArgumentOrder, typename... Args>
requires OutputSink<Sink> && CompiledFormat<std::remove_cvref_t<Format>>
static ErrorCode LibXR::Print::Writer::RunArgumentOrder ( Sink & sink,
const Format & ,
Args &&... args )
inlinestaticnodiscard

Runs one compiled format whose runtime pack order is provided separately from the call-site argument order.

执行一份已编译格式;其运行期打包顺序由独立的编译期参数顺序表提供。

This is used by brace-style frontends that allow repeated or reordered argument references such as {1} {0} while keeping the runtime bytecode stream itself strictly source-ordered. 该接口用于 brace 风格前端:它允许 {1} {0} 这种重复或重排参数引用, 同时保持运行期字节码流本身仍然严格按源串顺序执行。

Definition at line 44 of file writer.hpp.

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 }

◆ StoreArgument()

template<typename T >
static void LibXR::Print::Writer::StoreArgument ( uint8_t *& out,
const T & value )
inlinestaticprivate

Definition at line 284 of file writer.hpp.

285 {
286 std::memcpy(out, &value, sizeof(T));
287 out += sizeof(T);
288 }

◆ StoreArgumentsOrdered()

template<auto ArgumentInfoList, auto ArgumentOrder, typename Tuple >
static void LibXR::Print::Writer::StoreArgumentsOrdered ( uint8_t *& out,
Tuple & tuple )
inlinestaticprivate

Definition at line 302 of file writer.hpp.

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 }
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

◆ ToStringView()

template<typename T >
static constexpr std::string_view LibXR::Print::Writer::ToStringView ( const T & text)
inlinestaticnodiscardconstexprprivate

Definition at line 146 of file writer.hpp.

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 }

◆ TrimGeneralText()

static size_t LibXR::Print::Writer::TrimGeneralText ( char * text,
size_t size )
inlinestaticnodiscardprivate

Trims trailing zeros for general float output and removes a dangling decimal point when alternate form is absent. / 在未启用备用格式时修剪通用浮点输出的尾随零,并去掉孤立小数点

Definition at line 684 of file writer.hpp.

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 }

◆ UsesFloatTextBackend()

static constexpr bool LibXR::Print::Writer::UsesFloatTextBackend ( FormatType type)
inlinestaticnodiscardconstexprprivate

Returns whether one runtime type is handled by the shared float text backend. / 判断某个运行期类型是否由共享浮点文本后端处理

Definition at line 460 of file writer.hpp.

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 }

Field Documentation

◆ args

const uint8_t const uint8_t* LibXR::Print::Writer::args
private
Initial value:
{
return Executor<Sink, Profile>(sink, codes, args).Run()

Definition at line 1079 of file writer.hpp.

◆ codes

const uint8_t * LibXR::Print::Writer::codes
private

Definition at line 1079 of file writer.hpp.

◆ dependent_false_v

template<FormatPackKind K>
bool LibXR::Print::Writer::dependent_false_v = false
staticconstexprprivate

Definition at line 66 of file writer.hpp.

◆ f32_decimal_scales_u32

std::array<uint32_t, 10> LibXR::Print::Writer::f32_decimal_scales_u32
inlinestaticconstexprprivate
Initial value:
{
1U,
10U,
100U,
1000U,
10000U,
100000U,
1000000U,
10000000U,
100000000U,
1000000000U,
}

Decimal scales used by the narrow float32 fixed-precision fast path. / 窄 float32 定点快路径使用的十进制缩放表

Definition at line 70 of file writer.hpp.

70 {
71 1U,
72 10U,
73 100U,
74 1000U,
75 10000U,
76 100000U,
77 1000000U,
78 10000000U,
79 100000000U,
80 1000000000U,
81 };

◆ f32_u32_overflow_limit

float LibXR::Print::Writer::f32_u32_overflow_limit = 4294967296.0f
staticconstexprprivate

Largest finite float32 value whose integer part still fits in uint32_t. / 整数部分仍可放入 uint32_t 的最大 float32 值上界

Definition at line 68 of file writer.hpp.

◆ float_buffer_capacity

size_t LibXR::Print::Writer::float_buffer_capacity = 512
staticconstexprprivate

Definition at line 64 of file writer.hpp.

◆ unspecified_precision

uint8_t LibXR::Print::Writer::unspecified_precision = 0xFF
staticconstexprprivate

Emits the stack argument byte blob for one compiled argument list.

为某个已编译参数列表生成栈上参数字节块。

Definition at line 63 of file writer.hpp.


The documentation for this class was generated from the following file: