12#include "libxr_def.hpp"
17template <Print::Text Source,
typename... Args>
27template <
typename... Values>
36template <
typename T,
bool IsEnum = std::is_enum_v<T>>
45 using Type = std::underlying_type_t<T>;
54static constexpr bool runtime_string_always_false =
false;
56inline constexpr size_t runtime_string_unbounded_capacity =
57 std::numeric_limits<size_t>::max();
58inline constexpr size_t runtime_string_max_field_width =
59 std::numeric_limits<uint8_t>::max();
74[[nodiscard]]
constexpr size_t RuntimeStringFieldCapacity(Print::FormatPackKind pack)
76 constexpr size_t width = runtime_string_max_field_width;
77 constexpr size_t precision = runtime_string_max_field_width;
81 case Print::FormatPackKind::I32:
82 return 1U + precision;
83 case Print::FormatPackKind::I64:
84 return 1U + precision;
85 case Print::FormatPackKind::U32:
86 return 2U + precision;
87 case Print::FormatPackKind::U64:
88 return 2U + precision;
89 case Print::FormatPackKind::Pointer:
91 (precision > 2U *
sizeof(uintptr_t) ? precision : 2U *
sizeof(uintptr_t));
92 case Print::FormatPackKind::Character:
94 case Print::FormatPackKind::StringView:
95 return runtime_string_unbounded_capacity;
96 case Print::FormatPackKind::F32:
97 return 1U +
static_cast<size_t>(std::numeric_limits<float>::max_exponent10) + 2U +
99 case Print::FormatPackKind::F64:
100 return 1U +
static_cast<size_t>(std::numeric_limits<double>::max_exponent10) + 2U +
102 case Print::FormatPackKind::LongDouble:
103 return 1U +
static_cast<size_t>(std::numeric_limits<long double>::max_exponent10) +
107 return runtime_string_unbounded_capacity;
110[[nodiscard]]
constexpr bool RuntimeStringAddCapacity(
size_t& total,
size_t value)
112 if (value == runtime_string_unbounded_capacity ||
113 runtime_string_unbounded_capacity - total < value)
121template <
typename Built>
122[[nodiscard]]
consteval size_t RuntimeStringMaxFormattedSize(
size_t source_size)
124 size_t total = source_size;
125 for (
const auto& argument : Built::ArgumentList())
127 if (!RuntimeStringAddCapacity(total, RuntimeStringFieldCapacity(argument.pack)))
129 return runtime_string_unbounded_capacity;
150 using Decayed = std::remove_cvref_t<T>;
151 using Normalized =
typename RuntimeStringNormalized<Decayed>::Type;
153 static constexpr bool is_text =
154 std::is_array_v<Decayed> || std::is_same_v<Decayed, char*> ||
155 std::is_same_v<Decayed, const char*> || std::is_same_v<Decayed, std::string> ||
156 std::is_same_v<Decayed, std::string_view>;
158 static constexpr bool is_pointer =
159 std::is_pointer_v<Decayed> && !std::is_function_v<std::remove_pointer_t<Decayed>>;
161 static constexpr bool has_static_capacity =
163 (std::is_same_v<Decayed, std::nullptr_t> || is_pointer ||
164 std::is_integral_v<Normalized> || std::is_floating_point_v<Normalized>);
173template <
typename... Args>
176 template <
typename... CallArgs>
177 static constexpr bool matches = std::is_same_v<
188 std::string_view view;
203inline constexpr bool runtime_string_is_view_v =
212 char* data =
nullptr;
216 [[nodiscard]]
ErrorCode Write(std::string_view chunk)
218 if (capacity - size < chunk.size())
224 std::memcpy(data + size, chunk.data(), chunk.size());
225 size += chunk.size();
249template <
Print::Text Source =
"",
typename... Args>
253 static_assert((std::is_same_v<
254 Args,
typename Detail::RuntimeStringArgumentTraits<Args>::Decayed> &&
256 "LibXR::RuntimeStringView argument types must be unqualified "
259 "LibXR::RuntimeStringView formatted arguments cannot contain "
260 "runtime strings; use RuntimeStringView<> for text concatenation");
271 :
data_(other.data_),
276 other.data_ =
nullptr;
286 requires(Source.
Size() == 0 &&
sizeof...(Args) == 0)
295 requires(Source.
Size() == 0 &&
sizeof...(Args) == 0)
303 requires(Source.
Size() == 0 &&
sizeof...(Args) == 0)
310 template <
typename CharPtr>
311 requires(Source.
Size() == 0 &&
sizeof...(Args) == 0 &&
312 (std::is_same_v<CharPtr, char*> || std::is_same_v<CharPtr, const char*>))
321 requires(Source.
Size() == 0 &&
sizeof...(Args) == 0)
323 static_cast<void>(
AssignCopy(
static_cast<const char*
>(text)));
327 template <
typename First,
typename Second,
typename... Rest>
329 requires(Source.
Size() == 0 &&
sizeof...(Args) == 0)
331 static_cast<void>(
AssignConcat(std::forward<First>(first),
332 std::forward<Second>(second),
333 std::forward<Rest>(rest)...));
340 template <
typename... CallArgs>
342 requires((Source.
Size() != 0 ||
sizeof...(Args) != 0) &&
346 "LibXR::RuntimeStringView format argument types do not match "
349 static constexpr size_t max_size =
350 Detail::RuntimeStringMaxFormattedSize<Built>(Source.
Size());
351 static_assert(max_size != Detail::runtime_string_unbounded_capacity,
352 "LibXR::RuntimeStringView cannot retain unbounded formatted "
356 max_size, [&](
auto& sink)
357 {
return Print::FormatTo<Source>(sink, std::forward<CallArgs>(args)...); });
364 template <
typename... CallArgs>
366 requires((Source.
Size() != 0 ||
sizeof...(Args) != 0) &&
370 "LibXR::RuntimeStringView printf argument types do not match "
373 static constexpr size_t max_size =
374 Detail::RuntimeStringMaxFormattedSize<Built>(Source.Size());
375 static_assert(max_size != Detail::runtime_string_unbounded_capacity,
376 "LibXR::RuntimeStringView cannot retain unbounded formatted "
380 max_size, [&](
auto& sink)
381 {
return Print::PrintfTo<Source>(sink, std::forward<CallArgs>(args)...); });
385 [[nodiscard]]
constexpr std::string_view
View()
const
387 return data_ ==
nullptr ? std::string_view{} : std::string_view(
data_,
size_);
393 [[nodiscard]]
constexpr size_t Size()
const {
return size_; }
395 [[nodiscard]]
constexpr bool Empty()
const {
return size_ == 0; }
399 [[nodiscard]]
constexpr operator std::string_view()
const {
return View(); }
401 [[nodiscard]]
operator const char*()
const {
return CStr(); }
411 if (
data_ !=
nullptr)
437 if (payload_size == std::numeric_limits<size_t>::max())
445 if (
data_ !=
nullptr)
449 if (payload_size == 0)
454 data_ =
new char[payload_size + 1U];
472 std::memcpy(
data_, text.data(), text.size());
474 if (
data_ !=
nullptr)
476 data_[text.size()] =
'\0';
491 :
AssignCopy(std::string_view(text, std::strlen(text)));
503 template <
typename... Parts>
506 size_t total_size = 0;
509 auto count = [&](
auto&& part)
520 status = text.status;
522 else if (std::numeric_limits<size_t>::max() - total_size < text.view.size())
528 total_size += text.view.size();
531 (count(std::forward<Parts>(parts)), ...);
544 auto copy = [&](
auto&& part)
548 if (!text.view.empty())
550 std::memcpy(
data_ + offset, text.view.data(), text.view.size());
551 offset += text.view.size();
554 (copy(std::forward<Parts>(parts)), ...);
556 if (
data_ !=
nullptr)
558 data_[total_size] =
'\0';
575 template <
typename WriteFn>
578 if (
data_ ==
nullptr)
593 if (
data_ !=
nullptr)
595 data_[sink.size] =
'\0';
608 size_t bound)
noexcept
611 while (size < bound && text[size] !=
'\0')
625 template <
typename T>
629 using Bare = std::remove_cvref_t<T>;
630 if constexpr (Detail::runtime_string_is_view_v<T>)
632 const auto& retained = text;
637 else if constexpr (std::is_array_v<Bare> &&
638 std::is_same_v<std::remove_cv_t<std::remove_extent_t<Bare>>,
char>)
643 else if constexpr (std::is_same_v<Bare, std::string_view>)
645 return {.view = text};
647 else if constexpr (std::is_same_v<Bare, std::string>)
649 return {.view = std::string_view(text.data(), text.size())};
651 else if constexpr (std::is_same_v<Bare, std::nullptr_t>)
655 else if constexpr (std::is_same_v<Bare, char*> || std::is_same_v<Bare, const char*>)
657 return text ==
nullptr
661 .view = std::string_view(text, std::strlen(text))};
665 static_assert(Detail::runtime_string_always_false<T>,
666 "RuntimeStringView constructor only accepts text-like parts. "
667 "Use Reformat() or Reprintf() for numeric formatting.");
694template <
typename First,
typename Second,
typename... Rest>
static consteval bool Matches()
判断 Args... 是否与启用的转换项精确匹配 / Return whether Args... exactly match the enabled conversions
constexpr RuntimeStringView()=default
Constructs an empty valid view. / 构造一个空的有效视图。
constexpr ErrorCode Status() const
Returns the latest operation status. / 返回最近一次操作状态。
ErrorCode status_
最近一次构造或重写状态。 / Status of the latest construction or rewrite.
ErrorCode SetFailure(ErrorCode status)
记录最近一次失败,并在已有存储上保留一个有效的空 C 字符串。
RuntimeStringView(First &&first, Second &&second, Rest &&... rest)
Concatenates text parts into retained storage. / 拼接多个文本片段到保留存储。
RuntimeStringView(const char(&text)[N])
Copies one bounded const char array as text. / 按文本语义拷贝一个有界只读字符数组。
ErrorCode AssignCopy(const char *text)
C 字符串入口负责空指针检查,再进入统一的文本拷贝路径。
ErrorCode Reformat(CallArgs &&... args)
使用绑定的 brace-style 格式重写当前内容。
ErrorCode AssignFormatted(size_t max_size, WriteFn &&write)
格式化重写入口;首次调用按编译期上界分配,后续调用只覆盖已有存储。
RuntimeStringView(std::nullptr_t text)
constexpr size_t Size() const
Returns the text size excluding the trailing NUL. / 返回不含结尾 NUL 的文本长度。
static constexpr size_t BoundedTextLength(const char *text, size_t bound) noexcept
在已知边界内查找文本长度;遇到首个 \0 截断,否则使用整个数组长度。
ErrorCode AssignConcat(Parts &&... parts)
拼接构造的两遍流程:先校验并统计所有片段,再一次性写入。
const char * CStr() const
Returns a NUL-terminated C string. / 返回 NUL 结尾 C 字符串。
RuntimeStringView(CharPtr text)
RuntimeStringView(RuntimeStringView &&other) noexcept
ErrorCode AssignCopy(std::string_view text)
构造期文本拷贝入口;空字符串保持零分配。
ErrorCode Reprintf(CallArgs &&... args)
使用绑定的 printf-style 格式重写当前内容。
RuntimeStringView(std::string_view text)
Copies text into retained storage. / 拷贝文本到保留存储。
constexpr std::string_view View() const
Returns the current read-only view. / 返回当前只读视图。
RuntimeStringView(char(&text)[N])
ErrorCode EnsureCapacity(size_t payload_size)
为首个非空结果分配保留存储,已有存储不会再次扩容。
static constexpr Detail::RuntimeStringTextPart NormalizeConcatPart(T &&text)
把拼接构造支持的输入统一归一化为只读文本片段;普通拼接只接受文本类输入, 数值格式化必须显式走 Reformat() 或 Reprintf()。
constexpr bool Empty() const
Returns whether the current visible text is empty. / 返回当前可见文本是否为空。
@ OUT_OF_RANGE
超出范围 | Out of range
@ PTR_NULL
空指针 | Null pointer
@ OK
操作成功 | Operation successful
@ ARG_ERR
参数错误 | Argument error
RuntimeStringView(std::string_view) -> RuntimeStringView<>
Compile-time traits for formatted retained-string arguments.
Checks that a rewrite call uses exactly the argument types bound in RuntimeStringView<Source,...
Sink used by the second formatting pass to fill retained storage.
Normalizes enum arguments to their underlying type for capacity probes.
Normalized text part used by the copy/concatenation path.
Type-list tag used only for exact argument-list comparison.
作为 printf 格式源的结构化字符串字面量包装 / Structural literal wrapper used as the NTTP source for printf formats
constexpr size_t Size() const
返回不含结尾零字节的格式串长度 / Return the format length without the terminating zero byte