10#include "format_protocol.hpp"
11#include "print_contract.hpp"
50template <
typename Frontend>
55 "LibXR::Print::FormatCompiler: frontend must expose ErrorType, "
56 "SourceData(), and SourceSize()");
58 using Error =
typename Frontend::ErrorType;
66 template <
size_t BlobBytes,
size_t ArgCount>
70 std::array<uint8_t, BlobBytes>;
85 template <
size_t BlobBytes,
size_t ArgCount>
103 static constexpr size_t max_code_bytes = 3 * Frontend::SourceSize() + 1;
104 static constexpr size_t max_text_pool_bytes = Frontend::SourceSize();
105 static constexpr size_t max_arg_count = Frontend::SourceSize();
106 static constexpr uint8_t unspecified_precision = std::numeric_limits<uint8_t>::max();
115 static consteval void EmitByte(
auto& data,
size_t& out, uint8_t value)
129 template <
typename T>
130 static consteval void EmitNative(
auto& data,
size_t& out, T value)
132 auto bytes = std::bit_cast<std::array<uint8_t,
sizeof(T)>>(value);
133 for (
auto byte : bytes)
148 template <
typename T>
149 [[nodiscard]]
static consteval T
ReadNative(
const auto& data,
size_t& pos)
151 std::array<uint8_t,
sizeof(T)> bytes{};
152 for (
size_t i = 0; i <
sizeof(T); ++i)
154 bytes[i] = data[pos++];
156 return std::bit_cast<T>(bytes);
165 [[nodiscard]]
static consteval auto Failed(Error error)
183 case FormatOp::U32Dec:
184 case FormatOp::U32ZeroPadWidth:
185 case FormatOp::I32Dec:
186 case FormatOp::U32Binary:
187 case FormatOp::U32Octal:
188 case FormatOp::U32HexLower:
189 case FormatOp::U32HexUpper:
190 return FormatProfile::NarrowInt;
191 case FormatOp::StringRaw:
192 case FormatOp::CharacterRaw:
193 return FormatProfile::TextArg;
194 case FormatOp::GenericField:
195 return FormatProfile::None;
196 case FormatOp::TextInline:
197 case FormatOp::TextRef:
198 case FormatOp::TextSpace:
200 return FormatProfile::None;
203 return FormatProfile::None;
215 if (raw_integer_field && field.
type == FormatType::Signed32 &&
216 field.
pack == FormatPackKind::I32)
218 return FormatOp::I32Dec;
221 if (field.
type == FormatType::Unsigned32 && field.
pack == FormatPackKind::U32 &&
224 return FormatOp::U32Dec;
227 if (raw_integer_field && field.
type == FormatType::Binary32 &&
228 field.
pack == FormatPackKind::U32)
230 return FormatOp::U32Binary;
233 if (raw_integer_field && field.
type == FormatType::Octal32 &&
234 field.
pack == FormatPackKind::U32)
236 return FormatOp::U32Octal;
239 if (raw_integer_field && field.
type == FormatType::HexLower32 &&
240 field.
pack == FormatPackKind::U32)
242 return FormatOp::U32HexLower;
245 if (raw_integer_field && field.
type == FormatType::HexUpper32 &&
246 field.
pack == FormatPackKind::U32)
248 return FormatOp::U32HexUpper;
251 if (raw_text_field && field.
type == FormatType::Character &&
252 field.
pack == FormatPackKind::Character)
254 return FormatOp::CharacterRaw;
257 if (raw_text_field && field.
type == FormatType::String &&
258 field.
pack == FormatPackKind::StringView)
260 return FormatOp::StringRaw;
263 if (field.
type == FormatType::Unsigned32 && field.
pack == FormatPackKind::U32 &&
264 field.
flags ==
static_cast<uint8_t
>(FormatFlag::ZeroPad) && field.
fill ==
' ' &&
267 return FormatOp::U32ZeroPadWidth;
270 return FormatOp::GenericField;
279 return field.
flags == 0 && field.
fill ==
' ' && field.
width == 0 &&
280 field.
precision == unspecified_precision;
289 return (field.
flags == 0 ||
290 field.
flags ==
static_cast<uint8_t
>(FormatFlag::LeftAlign)) &&
292 field.
precision == unspecified_precision;
301 std::array<uint8_t, max_code_bytes>
304 std::array<uint8_t, max_text_pool_bytes>
306 std::array<FormatArgumentInfo, max_arg_count>
327 [[nodiscard]]
consteval Error
Text(
size_t offset,
size_t text_size)
334 if (text_size == 1 && Frontend::SourceData()[offset] ==
' ')
343 for (
size_t i = 0; i < text_size; ++i)
346 static_cast<uint8_t
>(Frontend::SourceData()[offset + i]));
354 return Error::TextOffsetOverflow;
356 if (text_size > std::numeric_limits<uint16_t>::max())
358 return Error::TextSizeOverflow;
365 for (
size_t i = 0; i < text_size; ++i)
368 static_cast<uint8_t
>(Frontend::SourceData()[offset + i]);
388 case FormatOp::U32Dec:
389 case FormatOp::I32Dec:
390 case FormatOp::U32Binary:
391 case FormatOp::U32Octal:
392 case FormatOp::U32HexLower:
393 case FormatOp::U32HexUpper:
394 case FormatOp::StringRaw:
395 case FormatOp::CharacterRaw:
397 case FormatOp::U32ZeroPadWidth:
400 case FormatOp::GenericField:
407 case FormatOp::TextInline:
408 case FormatOp::TextRef:
409 case FormatOp::TextSpace:
415 op == FormatOp::GenericField ? GenericProfileFor(field.
type) :
ProfileForOp(op);
455 template <
size_t CodeBytes,
size_t BlobBytes,
size_t ArgCount>
456 [[nodiscard]]
consteval auto Finish()
const
460 size_t scratch_in = 0;
465 auto op =
static_cast<FormatOp
>(
code_scratch[scratch_in++]);
466 EmitByte(result.codes, code_out,
static_cast<uint8_t
>(op));
468 if (op == FormatOp::TextInline)
473 EmitByte(result.codes, code_out,
byte);
482 const size_t payload_bytes = FormatOpPayloadBytes(op);
483 if (payload_bytes == 0)
488 if (op == FormatOp::TextRef)
492 size_t absolute_offset = CodeBytes + relative_offset;
493 if (absolute_offset > std::numeric_limits<uint16_t>::max())
495 result.compile_error = Error::TextOffsetOverflow;
498 EmitNative(result.codes, code_out,
static_cast<uint16_t
>(absolute_offset));
499 EmitNative(result.codes, code_out, text_size);
503 if (payload_bytes == 1)
509 if (op == FormatOp::GenericField)
511 for (
size_t i = 0; i < payload_bytes; ++i)
518 EmitByte(result.codes, code_out,
static_cast<uint8_t
>(FormatOp::End));
524 for (
size_t i = 0; i < ArgCount; ++i)
534 "LibXR::Print::FormatCompiler: frontend Walk(visitor) must accept "
535 "the shared builder and return ErrorType");
547 constexpr auto scratch = []()
consteval
554 if constexpr (scratch.frontend_error != Error::None)
556 return Failed(scratch.frontend_error);
560 return scratch.template Finish<scratch.FinalCodeBytes(), scratch.FinalBlobBytes(),
561 scratch.arg_count>();
可由共享后端读取源码信息的格式前端 / Format frontend exposing source metadata to the shared backend
可向指定 visitor 发射格式事件的前端 / Frontend that can emit format events into the supplied visitor