145 template <
typename Sink,
typename Format,
auto ArgumentOrder,
typename... Args>
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");
155 Built::template Matches<Args...>(),
156 "LibXR::Print::Writer::RunArgumentOrder: format arguments do not match");
158 return RunTaggedArgumentOrder<Sink, Built::ArgumentList(), ArgumentOrder,
159 Built::Profile()>(sink, Built::Codes().data(),
160 std::forward<Args>(args)...);
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();
178 [[nodiscard]]
static constexpr bool HasFlag(uint8_t flags, uint8_t bit)
180 return (flags & bit) != 0;
192 uint8_t precision = unspecified_precision;
200 [[nodiscard]]
constexpr bool LeftAlign()
const
202 return Writer::HasFlag(flags,
static_cast<uint8_t
>(FormatFlag::LeftAlign));
211 [[nodiscard]]
constexpr bool ForceSign()
const
213 return Writer::HasFlag(flags,
static_cast<uint8_t
>(FormatFlag::ForceSign));
221 [[nodiscard]]
constexpr bool CenterAlign()
const
223 return Writer::HasFlag(flags,
static_cast<uint8_t
>(FormatFlag::CenterAlign));
232 [[nodiscard]]
constexpr bool SpaceSign()
const
234 return Writer::HasFlag(flags,
static_cast<uint8_t
>(FormatFlag::SpaceSign));
242 [[nodiscard]]
constexpr bool Alternate()
const
244 return Writer::HasFlag(flags,
static_cast<uint8_t
>(FormatFlag::Alternate));
252 [[nodiscard]]
constexpr bool ZeroPad()
const
254 return Writer::HasFlag(flags,
static_cast<uint8_t
>(FormatFlag::ZeroPad));
262 [[nodiscard]]
constexpr bool UpperCase()
const
264 return Writer::HasFlag(flags,
static_cast<uint8_t
>(FormatFlag::UpperCase));
272 [[nodiscard]]
constexpr bool HasPrecision()
const
274 return precision != unspecified_precision;
286 [[nodiscard]]
static constexpr size_t BoundedTextLength(
const char (&text)[N])
noexcept;
295 template <
typename T>
296 [[nodiscard]]
static constexpr std::string_view ToStringView(
const T& text);
306 template <FormatPackKind pack,
typename T>
307 [[nodiscard]]
static constexpr auto PackValue(T&& value);
316 template <
typename T>
317 static void StoreArgument(uint8_t*& out,
const T& value);
325 template <auto ArgumentInfoList>
326 [[nodiscard]]
static consteval size_t PackedArgumentBytes();
339 template <auto ArgumentInfoList, auto ArgumentOrder,
typename Tuple>
340 static void StoreArgumentsOrdered(uint8_t*& out, Tuple& tuple);
358 template <std::
unsigned_
integral UInt, u
int8_t Base>
359 [[nodiscard]]
static consteval size_t UnsignedDigitCapacity();
373 template <u
int8_t Base,
bool UpperCase = false,
size_t N, std::
unsigned_
integral UInt>
374 [[nodiscard]]
static size_t AppendUnsigned(
char (&out)[N], UInt value);
384 [[nodiscard]]
static size_t AppendSmallUnsigned(
char (&out)[N], uint8_t value);
393 [[nodiscard]]
static constexpr size_t FieldPadding(uint8_t width,
size_t payload_size);
402 [[nodiscard]]
static constexpr size_t IntegerPrecisionZeros(
const Spec& spec,
414 template <std::
unsigned_
integral UInt>
415 [[nodiscard]]
static constexpr std::string_view IntegerPrefix(FormatType type,
436 template <std::
unsigned_
integral UInt>
437 [[nodiscard]]
static size_t ApplyAlternateOctal(
char* digits,
size_t digit_count,
438 const Spec& spec, UInt value);
447 [[nodiscard]]
static constexpr bool UsesFloatTextBackend(FormatType type);
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);
486 [[nodiscard]]
static bool AppendBufferChar(
char* buffer,
size_t capacity,
size_t& size,
499 [[nodiscard]]
static bool AppendBufferText(
char* buffer,
size_t capacity,
size_t& size,
500 std::string_view text);
513 [[nodiscard]]
static bool AppendBufferU32ZeroPad(
char* buffer,
size_t capacity,
514 size_t& size, uint32_t value,
517#if LIBXR_PRINT_ENABLE_FLOAT
523 template <
typename Float>
531 template <
typename Float>
532 struct ScientificDigits;
541 template <
typename Float>
542 [[nodiscard]]
static Float Power10(
int exponent);
553 template <
typename Float>
554 [[nodiscard]]
static Float RoundDecimal(Float value, uint8_t precision);
564 template <
typename Float>
565 [[nodiscard]]
static ScientificDigits<Float> RoundScientificDigits(Float value,
575 template <
typename Float>
576 [[nodiscard]]
static DecimalScale<Float> NormalizeDecimal(Float value);
586 template <
typename Float>
587 [[nodiscard]]
static uint8_t ExtractDigit(Float& value, Float scale);
597 [[nodiscard]]
static size_t TrimGeneralText(
char* text,
size_t size);
610 template <
typename Float>
611 [[nodiscard]]
static bool FormatFixedText(Float value, uint8_t precision,
612 bool alternate,
char* out,
size_t& out_size);
623 [[nodiscard]]
static bool AppendExponentText(
char* out,
size_t& out_size,
int exponent,
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);
655 template <
typename Float>
656 [[nodiscard]]
static bool FormatFloatText(FormatType type,
const Spec& spec,
657 Float value,
char* out,
size_t& out_size);
661 class ArgumentReader;
663 template <OutputSink Sink>
677 template <OutputSink Sink, FormatProfile Profile>
678 [[nodiscard]]
static LIBXR_NOINLINE
ErrorCode Execute(Sink& sink,
const uint8_t* codes,
681 return Executor<Sink>(sink, codes, args).template Run<Profile>();
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)
703 if constexpr (ArgumentInfoList.size() == 0)
705 return Execute<Sink, Profile>(sink, codes,
nullptr);
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;
713 StoreArgumentsOrdered<ArgumentInfoList, ArgumentOrder>(cursor, tuple);
714 return Execute<Sink, Profile>(sink, codes, packed);