11[[nodiscard]]
constexpr bool IsDigit(
char ch)
13 return ch >=
'0' && ch <=
'9';
21[[nodiscard]]
constexpr bool IsAlign(
char ch)
23 return ch ==
'<' || ch ==
'>' || ch ==
'^';
31[[nodiscard]]
constexpr Align ParseAlign(
char ch)
51[[nodiscard]]
constexpr bool HasEmbeddedNul(std::string_view source)
53 for (
char ch : source)
68[[nodiscard]]
constexpr bool IsSupportedPresentation(
char ch)
102template <
typename UInt>
103[[nodiscard]]
consteval Error ParseUnsigned(std::string_view source,
size_t& pos,
104 UInt limit, UInt& value)
106 static_assert(std::is_unsigned_v<UInt>);
109 if (pos >= source.size() || !IsDigit(source[pos]))
111 return Error::InvalidSpecifier;
114 while (pos < source.size() && IsDigit(source[pos]))
116 auto digit =
static_cast<UInt
>(source[pos] -
'0');
117 if (value >
static_cast<UInt
>((limit - digit) / 10))
119 return Error::NumberOverflow;
121 value =
static_cast<UInt
>(value * 10 + digit);
146[[nodiscard]]
consteval Error ParseFieldHead(std::string_view source,
size_t& pos,
150 if (pos >= source.size())
152 return Error::UnexpectedEnd;
155 if (source[pos] ==
':' || source[pos] ==
'}')
159 return Error::MixedIndexing;
167 if (!IsDigit(source[pos]))
169 return Error::InvalidArgumentIndex;
174 ParseUnsigned(source, pos, std::numeric_limits<size_t>::max(), index);
175 if (error != Error::None)
182 return Error::MixedIndexing;
185 if (!Config::enable_explicit_argument_indexing)
187 return Error::ManualIndexingDisabled;
191 field.arg_index = index;
202[[nodiscard]]
consteval Error ParseFormatSpec(std::string_view source,
size_t& pos,
205 if (pos >= source.size())
207 return Error::UnexpectedEnd;
210 if (pos + 1 < source.size() && IsAlign(source[pos + 1]))
212 if (source[pos] ==
'{' || source[pos] ==
'}')
214 return Error::InvalidSpecifier;
216 field.fill = source[pos];
217 field.align = ParseAlign(source[pos + 1]);
220 else if (IsAlign(source[pos]))
222 field.align = ParseAlign(source[pos]);
226 if (pos < source.size() &&
227 (source[pos] ==
'+' || source[pos] ==
'-' || source[pos] ==
' '))
229 field.force_sign = source[pos] ==
'+';
230 field.space_sign = source[pos] ==
' ';
234 if (pos < source.size() && source[pos] ==
'#')
236 if (!Config::enable_alternate)
238 return Error::InvalidSpecifier;
240 field.alternate =
true;
244 if (pos < source.size() && source[pos] ==
'0')
246 field.zero_pad =
true;
250 if (pos < source.size() && source[pos] ==
'{')
252 return Error::DynamicField;
255 if (pos < source.size() && IsDigit(source[pos]))
257 if (!Config::enable_width)
259 return Error::InvalidSpecifier;
261 auto error = ParseUnsigned(source, pos, std::numeric_limits<uint8_t>::max(),
263 if (error != Error::None)
269 if (pos < source.size() && source[pos] ==
'.')
271 if (!Config::enable_precision)
273 return Error::InvalidSpecifier;
277 if (pos < source.size() && source[pos] ==
'{')
279 return Error::DynamicField;
282 field.has_precision =
true;
283 auto error = ParseUnsigned(
284 source, pos,
static_cast<uint8_t
>(std::numeric_limits<uint8_t>::max() - 1),
286 if (error != Error::None)
292 if (pos < source.size() && source[pos] !=
'}')
294 field.presentation = source[pos++];
295 if (!IsSupportedPresentation(field.presentation))
297 return Error::InvalidPresentation;
312[[nodiscard]]
consteval Error ParseField(std::string_view source,
size_t& pos,
317 if (pos >= source.size())
319 return Error::UnexpectedEnd;
322 auto error = ParseFieldHead(source, pos, indexing, field);
323 if (error != Error::None)
328 if (pos < source.size() && source[pos] !=
':' && source[pos] !=
'}')
330 return Error::InvalidArgumentIndex;
333 if (pos < source.size() && source[pos] ==
':')
336 error = ParseFormatSpec(source, pos, field);
337 if (error != Error::None)
343 if (pos >= source.size())
345 return Error::UnexpectedEnd;
347 if (source[pos] !=
'}')
349 return Error::InvalidSpecifier;
brace 字段自动索引与手动索引的源级状态 / Source-level indexing mode for automatic versus manual brace fields
bool uses_auto
automatic field numbering is in use / 正在使用自动编号
size_t next_auto_index
next automatic argument index / 下一个自动参数索引
bool uses_manual
manual field numbering is in use / 正在使用手动编号