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 "../libxr_def.hpp"
18#include "format_argument.hpp"
19#include "format_protocol.hpp"
20#include "print_contract.hpp"
21
22namespace LibXR::Print
23{
24namespace Detail::WriterFloatLimit
25{
32[[nodiscard]] constexpr size_t DecimalDigitCount(size_t value)
33{
34 size_t digits = 1;
35 while (value >= 10)
36 {
37 value /= 10;
38 ++digits;
39 }
40 return digits;
41}
42
49template <typename Float>
50[[nodiscard]] constexpr size_t FixedTextLimit()
51{
52 constexpr size_t decimal_point =
53 (Config::max_float_precision != 0 || Config::enable_alternate) ? 1U : 0U;
54 return Config::max_float_integer_digits + decimal_point +
55 static_cast<size_t>(Config::max_float_precision);
57
64template <typename Float>
65[[nodiscard]] constexpr size_t ScientificTextLimit()
66{
67 constexpr size_t decimal_point =
68 (Config::max_float_precision != 0 || Config::enable_alternate) ? 1U : 0U;
69 constexpr size_t exponent_digits =
70 DecimalDigitCount(static_cast<size_t>(std::numeric_limits<Float>::max_exponent10));
71 return 1U + decimal_point + static_cast<size_t>(Config::max_float_precision) + 2U +
72 exponent_digits;
73}
74
81template <typename Float>
82[[nodiscard]] constexpr size_t FloatTextLimit()
83{
84 constexpr size_t fixed_limit = FixedTextLimit<Float>();
85 constexpr size_t scientific_limit = ScientificTextLimit<Float>();
86 return fixed_limit > scientific_limit ? fixed_limit : scientific_limit;
87}
94[[nodiscard]] constexpr size_t ComputeBufferCapacity()
96 size_t capacity = 4;
97 if constexpr (Config::enable_float_fixed || Config::enable_float_scientific ||
98 Config::enable_float_general)
99 {
100 capacity = FloatTextLimit<float>();
102 if constexpr (Config::enable_float_double)
103 {
104 constexpr size_t double_limit = FloatTextLimit<double>();
105 capacity = capacity > double_limit ? capacity : double_limit;
106 }
107 if constexpr (Config::enable_float_long_double)
108 {
109 constexpr size_t long_double_limit = FloatTextLimit<long double>();
110 capacity = capacity > long_double_limit ? capacity : long_double_limit;
111 }
112 return capacity;
113}
114} // namespace Detail::WriterFloatLimit
115
121{
122 public:
145 template <typename Sink, typename Format, auto ArgumentOrder, typename... Args>
147 [[nodiscard]] static ErrorCode RunArgumentOrder(Sink& sink, const Format&,
148 Args&&... args)
149 {
150 using Built = std::remove_cvref_t<Format>;
151 static_assert(ArgumentOrder.size() == Built::ArgumentList().size(),
152 "LibXR::Print::Writer: argument reorder list must match the "
153 "compiled field count");
154 static_assert(
155 Built::template Matches<Args...>(),
156 "LibXR::Print::Writer::RunArgumentOrder: format arguments do not match");
157
158 return RunTaggedArgumentOrder<Sink, Built::ArgumentList(), ArgumentOrder,
159 Built::Profile()>(sink, Built::Codes().data(),
160 std::forward<Args>(args)...);
161 }
162
163 private:
168 static constexpr uint8_t unspecified_precision = 0xFF;
169 template <FormatPackKind K>
170 static constexpr bool dependent_false_v = false;
171 static constexpr size_t float_buffer_capacity =
172 Detail::WriterFloatLimit::ComputeBufferCapacity();
173
178 [[nodiscard]] static constexpr bool HasFlag(uint8_t flags, uint8_t bit)
179 {
180 return (flags & bit) != 0;
181 }
182
187 struct Spec
188 {
189 uint8_t flags = 0;
190 char fill = ' ';
191 uint8_t width = 0;
194
200 [[nodiscard]] constexpr bool LeftAlign() const
201 {
202 return Writer::HasFlag(flags, static_cast<uint8_t>(FormatFlag::LeftAlign));
203 }
204
211 [[nodiscard]] constexpr bool ForceSign() const
212 {
213 return Writer::HasFlag(flags, static_cast<uint8_t>(FormatFlag::ForceSign));
214 }
215
221 [[nodiscard]] constexpr bool CenterAlign() const
223 return Writer::HasFlag(flags, static_cast<uint8_t>(FormatFlag::CenterAlign));
224 }
225
232 [[nodiscard]] constexpr bool SpaceSign() const
233 {
234 return Writer::HasFlag(flags, static_cast<uint8_t>(FormatFlag::SpaceSign));
235 }
236
242 [[nodiscard]] constexpr bool Alternate() const
243 {
244 return Writer::HasFlag(flags, static_cast<uint8_t>(FormatFlag::Alternate));
245 }
246
252 [[nodiscard]] constexpr bool ZeroPad() const
253 {
254 return Writer::HasFlag(flags, static_cast<uint8_t>(FormatFlag::ZeroPad));
255 }
256
262 [[nodiscard]] constexpr bool UpperCase() const
263 {
264 return Writer::HasFlag(flags, static_cast<uint8_t>(FormatFlag::UpperCase));
265 }
266
272 [[nodiscard]] constexpr bool HasPrecision() const
273 {
275 }
276 };
277
285 template <size_t N>
286 [[nodiscard]] static constexpr size_t BoundedTextLength(const char (&text)[N]) noexcept;
287
295 template <typename T>
296 [[nodiscard]] static constexpr std::string_view ToStringView(const T& text);
297
306 template <FormatPackKind pack, typename T>
307 [[nodiscard]] static constexpr auto PackValue(T&& value);
308
316 template <typename T>
317 static void StoreArgument(uint8_t*& out, const T& value);
318
325 template <auto ArgumentInfoList>
326 [[nodiscard]] static consteval size_t PackedArgumentBytes();
327
339 template <auto ArgumentInfoList, auto ArgumentOrder, typename Tuple>
340 static void StoreArgumentsOrdered(uint8_t*& out, Tuple& tuple);
341
358 template <std::unsigned_integral UInt, uint8_t Base>
359 [[nodiscard]] static consteval size_t UnsignedDigitCapacity();
360
373 template <uint8_t Base, bool UpperCase = false, size_t N, std::unsigned_integral UInt>
374 [[nodiscard]] static size_t AppendUnsigned(char (&out)[N], UInt value);
375
383 template <size_t N>
384 [[nodiscard]] static size_t AppendSmallUnsigned(char (&out)[N], uint8_t value);
385
393 [[nodiscard]] static constexpr size_t FieldPadding(uint8_t width, size_t payload_size);
402 [[nodiscard]] static constexpr size_t IntegerPrecisionZeros(const Spec& spec,
403 size_t digit_count);
404
414 template <std::unsigned_integral UInt>
415 [[nodiscard]] static constexpr std::string_view IntegerPrefix(FormatType type,
416 const Spec& spec,
417 UInt value);
418
436 template <std::unsigned_integral UInt>
437 [[nodiscard]] static size_t ApplyAlternateOctal(char* digits, size_t digit_count,
438 const Spec& spec, UInt value);
439
447 [[nodiscard]] static constexpr bool UsesFloatTextBackend(FormatType type);
448
456 [[nodiscard]] static constexpr bool FloatEnabled(FormatType type);
462 [[nodiscard]] static constexpr uint8_t DefaultFloatPrecision();
473 template <typename Float>
474 [[nodiscard]] static bool ExceedsFixedIntegerDigits(Float value, uint8_t precision);
475
486 [[nodiscard]] static bool AppendBufferChar(char* buffer, size_t capacity, size_t& size,
487 char ch);
488
499 [[nodiscard]] static bool AppendBufferText(char* buffer, size_t capacity, size_t& size,
500 std::string_view text);
501
513 [[nodiscard]] static bool AppendBufferU32ZeroPad(char* buffer, size_t capacity,
514 size_t& size, uint32_t value,
515 uint8_t width);
516
517#if LIBXR_PRINT_ENABLE_FLOAT
523 template <typename Float>
524 struct DecimalScale;
525
531 template <typename Float>
532 struct ScientificDigits;
533
541 template <typename Float>
542 [[nodiscard]] static Float Power10(int exponent);
543
553 template <typename Float>
554 [[nodiscard]] static Float RoundDecimal(Float value, uint8_t precision);
555
564 template <typename Float>
565 [[nodiscard]] static ScientificDigits<Float> RoundScientificDigits(Float value,
566 uint8_t precision);
567
575 template <typename Float>
576 [[nodiscard]] static DecimalScale<Float> NormalizeDecimal(Float value);
577
586 template <typename Float>
587 [[nodiscard]] static uint8_t ExtractDigit(Float& value, Float scale);
588
597 [[nodiscard]] static size_t TrimGeneralText(char* text, size_t size);
598
610 template <typename Float>
611 [[nodiscard]] static bool FormatFixedText(Float value, uint8_t precision,
612 bool alternate, char* out, size_t& out_size);
613
623 [[nodiscard]] static bool AppendExponentText(char* out, size_t& out_size, int exponent,
624 bool upper_case);
625
638 template <typename Float>
639 [[nodiscard]] static bool FormatScientificText(Float value, uint8_t precision,
640 bool alternate, bool upper_case,
641 char* out, size_t& out_size);
642
655 template <typename Float>
656 [[nodiscard]] static bool FormatFloatText(FormatType type, const Spec& spec,
657 Float value, char* out, size_t& out_size);
658#endif
659
660 class CodeReader;
661 class ArgumentReader;
662
663 template <OutputSink Sink>
664 class Executor;
665
677 template <OutputSink Sink, FormatProfile Profile>
678 [[nodiscard]] static LIBXR_NOINLINE ErrorCode Execute(Sink& sink, const uint8_t* codes,
679 const uint8_t* args)
680 {
681 return Executor<Sink>(sink, codes, args).template Run<Profile>();
682 }
683
698 template <OutputSink Sink, auto ArgumentInfoList, auto ArgumentOrder,
699 FormatProfile Profile, typename... Args>
700 [[nodiscard]] static LIBXR_NOINLINE ErrorCode
701 RunTaggedArgumentOrder(Sink& sink, const uint8_t* codes, Args&&... args)
702 {
703 if constexpr (ArgumentInfoList.size() == 0)
704 {
705 return Execute<Sink, Profile>(sink, codes, nullptr);
706 }
707 else
708 {
709 constexpr size_t packed_arg_bytes = PackedArgumentBytes<ArgumentInfoList>();
710 uint8_t packed[packed_arg_bytes];
711 auto tuple = std::forward_as_tuple(std::forward<Args>(args)...);
712 auto* cursor = packed;
714 return Execute<Sink, Profile>(sink, codes, packed);
715 }
716 }
717};
718
719// These implementation headers form an ordered dependency chain.
720// clang-format off
721#include "writer/writer_argument.hpp"
722#include "writer/writer_integer.hpp"
723#if LIBXR_PRINT_ENABLE_FLOAT
724#include "writer/writer_float_runtime.hpp"
725#include "writer/writer_float_math.hpp"
726#include "writer/writer_float_fixed.hpp"
727#include "writer/writer_float_general.hpp"
728#endif
729#include "writer/writer_reader.hpp"
730#include "writer/writer_executor.hpp"
731// clang-format on
732} // namespace LibXR::Print
运行期参数字节块的顺序读取器 / Sequential reader for the packed runtime argument byte blob
Definition writer.hpp:90
编译后记录流的顺序读取器 / Sequential reader for the compiled record stream
Definition writer.hpp:12
按输出端共享重后端、按调用点 profile 裁剪操作码分发的字节码执行器 / Per-sink bytecode executor with shared heavy backends and per...
Definition writer.hpp:12
运行期 writer,负责打包调用点参数并执行编译好的字节流 / Runtime writer that packs call-site arguments and executes the compi...
Definition writer.hpp:121
static constexpr bool HasFlag(uint8_t flags, uint8_t bit)
判断某个已解码字段修饰位是否被设置 / Test whether one decoded field-spec bit is set
Definition writer.hpp:178
static constexpr size_t IntegerPrecisionZeros(const Spec &spec, size_t digit_count)
返回整数精度引入的额外前导零个数 / Return the extra leading-zero count introduced by integer precision
Definition writer.hpp:101
static ErrorCode RunArgumentOrder(Sink &sink, const Format &, Args &&... args)
执行一份编译格式;它的字段顺序与源参数顺序可以不同 / Run one compiled format whose field order and source argument order may d...
Definition writer.hpp:147
static consteval size_t PackedArgumentBytes()
返回一组编译参数元信息在运行期需要的打包字节数 / Return the runtime packed-byte size required by one compiled argument metad...
Definition writer.hpp:211
static size_t AppendSmallUnsigned(char(&out)[N], uint8_t value)
以十进制形式追加一个较小的无符号整数 / Append one small unsigned integer in base 10
Definition writer.hpp:77
static constexpr std::string_view IntegerPrefix(FormatType type, const Spec &spec, UInt value)
返回放在数字载荷之外的备用格式前缀 / Return the alternate-form prefix carried outside the digit payload
Definition writer.hpp:118
static constexpr bool UsesFloatTextBackend(FormatType type)
判断这个字段类型是否走共享的浮点文本输出路径 / Return whether this field type is printed by the shared float-text path
static constexpr auto PackValue(T &&value)
将一个运行期实参转换为某个编译参数槽要求的打包存储形态 / Convert one runtime argument into the packed storage shape required by ...
Definition writer.hpp:88
static constexpr size_t FieldPadding(uint8_t width, size_t payload_size)
返回把某段载荷扩展到目标字段宽度所需的填充长度 / Return the padding width needed to expand one payload to the requested fiel...
Definition writer.hpp:89
static constexpr std::string_view ToStringView(const T &text)
将一个字符串类运行期参数归一化为 std::string_view / Normalize one string-like runtime argument into std::string_view
Definition writer.hpp:46
static consteval size_t UnsignedDigitCapacity()
返回某个无符号整数在指定进制下所需的最大数字个数 / Return the maximum digit count required for one unsigned integer under the...
Definition writer.hpp:10
static LIBXR_NOINLINE ErrorCode RunTaggedArgumentOrder(Sink &sink, const uint8_t *codes, Args &&... args)
先打包转发后的运行期参数,再执行编译字节流 / Pack forwarded runtime arguments, then execute the compiled byte stream
Definition writer.hpp:701
static bool AppendBufferText(char *buffer, size_t capacity, size_t &size, std::string_view text)
向有界本地格式化缓冲区追加一段文本 / Append one text span to a bounded local formatting buffer
static constexpr uint8_t DefaultFloatPrecision()
返回格式串没有显式写精度时使用的默认浮点精度 / Return the default float precision used when the format string did not speci...
static constexpr bool FloatEnabled(FormatType type)
判断这个浮点字段类型是否被当前功能开关启用 / Return whether this float field type is enabled by current feature switches
static bool AppendBufferU32ZeroPad(char *buffer, size_t capacity, size_t &size, uint32_t value, uint8_t width)
追加一个 uint32_t 十进制值,并在前面补零到目标宽度 / Append one uint32_t decimal value and pad leading zeros up to the ta...
static size_t ApplyAlternateOctal(char *digits, size_t digit_count, const Spec &spec, UInt value)
直接在已生成的数字载荷上应用 %#o 的特殊规则 / Apply %#o special rules directly onto the generated digit payload
Definition writer.hpp:151
static void StoreArgument(uint8_t *&out, const T &value)
把一个已打包值复制进参数字节块,并推进写指针 / Copy one packed value into the argument byte blob and advance the cursor
Definition writer.hpp:197
static size_t AppendUnsigned(char(&out)[N], UInt value)
把一个无符号整数写进调用方提供的定长数字缓冲区 / Append one unsigned integer into a caller-provided fixed-size digit buffer
Definition writer.hpp:38
static void StoreArgumentsOrdered(uint8_t *&out, Tuple &tuple)
按字段执行顺序把运行期参数打包成最终字节块 / Pack runtime arguments into the final byte blob in field execution order
Definition writer.hpp:234
static bool ExceedsFixedIntegerDigits(Float value, uint8_t precision)
判断定点形态的浮点输出是否会超出当前配置的整数位数上限 / Return whether fixed-shape float output would exceed the configured int...
static constexpr size_t BoundedTextLength(const char(&text)[N]) noexcept
返回一个 char 数组参数在边界内的 C 字符串长度 / Return the bounded C-string length stored inside one char array argumen...
Definition writer.hpp:20
static constexpr uint8_t unspecified_precision
为某个已编译参数列表生成栈上参数字节块 / Emit the stack argument byte blob for one compiled argument list
Definition writer.hpp:168
static LIBXR_NOINLINE ErrorCode Execute(Sink &sink, const uint8_t *codes, const uint8_t *args)
使用一份已打包参数字节块执行一段编译字节流 / Execute one compiled byte stream against one already packed argument blob
Definition writer.hpp:678
static bool AppendBufferChar(char *buffer, size_t capacity, size_t &size, char ch)
向有界本地格式化缓冲区追加一个字符 / Append one character to a bounded local formatting buffer
Writer 可执行的编译后格式对象 / Compiled format object executable by Writer.
接收编译格式输出的写入端 / Output endpoint accepted by compiled format writers
ErrorCode
定义错误码枚举
运行期对单个字段描述字节组的解码视图 / Runtime view of one decoded field specification byte group
Definition writer.hpp:188
constexpr bool ZeroPad() const
判断是否请求了零填充 / Return whether zero-padding is requested
Definition writer.hpp:252
constexpr bool UpperCase() const
判断是否请求了大写输出 / Return whether uppercase output is requested
Definition writer.hpp:262
constexpr bool SpaceSign() const
判断是否请求了正值前补空格的符号策略 / Return whether space-sign output for positive values is requested
Definition writer.hpp:232
constexpr bool LeftAlign() const
判断是否请求了左对齐 / Return whether left alignment is requested
Definition writer.hpp:200
constexpr bool HasPrecision() const
判断是否显式指定了精度 / Return whether precision was explicitly specified
Definition writer.hpp:272
uint8_t width
field width, or zero when absent / 字段宽度,未指定时为 0
Definition writer.hpp:191
constexpr bool Alternate() const
判断是否请求了备用格式 / Return whether alternate form is requested
Definition writer.hpp:242
constexpr bool ForceSign() const
判断是否请求了显式正号输出 / Return whether explicit plus-sign output is requested
Definition writer.hpp:211
constexpr bool CenterAlign() const
判断是否请求了居中对齐 / Return whether center alignment is requested
Definition writer.hpp:221
char fill
field fill character / 字段填充字符
Definition writer.hpp:190
uint8_t flags
FormatFlag bitset / 字段修饰位集合
Definition writer.hpp:189