14[[nodiscard]]
constexpr bool IsDigit(
char ch) {
return ch >=
'0' && ch <=
'9'; }
23[[nodiscard]]
constexpr bool IsAlign(
char ch)
25 return ch ==
'<' || ch ==
'>' || ch ==
'^';
35[[nodiscard]]
constexpr Align ParseAlign(
char ch)
57[[nodiscard]]
constexpr bool HasEmbeddedNul(std::string_view source)
59 for (
char ch : source)
76[[nodiscard]]
constexpr bool IsSupportedPresentation(
char ch)
113template <
typename UInt>
114[[nodiscard]]
consteval Error ParseUnsigned(std::string_view source,
size_t& pos,
115 UInt limit, UInt& value)
117 static_assert(std::is_unsigned_v<UInt>);
120 if (pos >= source.size() || !IsDigit(source[pos]))
122 return Error::InvalidSpecifier;
125 while (pos < source.size() && IsDigit(source[pos]))
127 auto digit =
static_cast<UInt
>(source[pos] -
'0');
128 if (value >
static_cast<UInt
>((limit - digit) / 10))
130 return Error::NumberOverflow;
132 value =
static_cast<UInt
>(value * 10 + digit);
161[[nodiscard]]
consteval Error ParseFieldHead(std::string_view source,
size_t& pos,
164 if (pos >= source.size())
166 return Error::UnexpectedEnd;
169 if (source[pos] ==
':' || source[pos] ==
'}')
173 return Error::MixedIndexing;
181 if (!IsDigit(source[pos]))
183 return Error::InvalidArgumentIndex;
187 auto error = ParseUnsigned(source, pos, std::numeric_limits<size_t>::max(), index);
188 if (error != Error::None)
195 return Error::MixedIndexing;
198 if (!Config::enable_explicit_argument_indexing)
200 return Error::ManualIndexingDisabled;
204 field.arg_index = index;
218[[nodiscard]]
consteval Error ParseFormatSpec(std::string_view source,
size_t& pos,
221 if (pos >= source.size())
223 return Error::UnexpectedEnd;
226 if (pos + 1 < source.size() && IsAlign(source[pos + 1]))
228 if (source[pos] ==
'{' || source[pos] ==
'}')
230 return Error::InvalidSpecifier;
232 field.fill = source[pos];
233 field.align = ParseAlign(source[pos + 1]);
236 else if (IsAlign(source[pos]))
238 field.align = ParseAlign(source[pos]);
242 if (pos < source.size() &&
243 (source[pos] ==
'+' || source[pos] ==
'-' || source[pos] ==
' '))
245 if (source[pos] ==
'+')
247 field.force_sign =
true;
249 else if (source[pos] ==
' ')
251 field.space_sign =
true;
259 if (pos < source.size() && source[pos] ==
'#')
261 if (!Config::enable_alternate)
263 return Error::InvalidSpecifier;
265 field.alternate =
true;
269 if (pos < source.size() && source[pos] ==
'0')
271 field.zero_pad =
true;
275 if (pos < source.size() && source[pos] ==
'{')
277 return Error::DynamicField;
280 if (pos < source.size() && IsDigit(source[pos]))
282 if (!Config::enable_width)
284 return Error::InvalidSpecifier;
287 ParseUnsigned(source, pos, std::numeric_limits<uint8_t>::max(), field.width);
288 if (error != Error::None)
294 if (pos < source.size() && source[pos] ==
'.')
296 if (!Config::enable_precision)
298 return Error::InvalidSpecifier;
302 if (pos < source.size() && source[pos] ==
'{')
304 return Error::DynamicField;
307 field.has_precision =
true;
308 auto error = ParseUnsigned(
309 source, pos,
static_cast<uint8_t
>(std::numeric_limits<uint8_t>::max() - 1),
311 if (error != Error::None)
317 if (pos < source.size() && source[pos] !=
'}')
319 field.presentation = source[pos++];
320 if (!IsSupportedPresentation(field.presentation))
322 return Error::InvalidPresentation;
340[[nodiscard]]
consteval Error ParseField(std::string_view source,
size_t& pos,
344 if (pos >= source.size())
346 return Error::UnexpectedEnd;
349 auto error = ParseFieldHead(source, pos, indexing, field);
350 if (error != Error::None)
355 if (pos < source.size() && source[pos] !=
':' && source[pos] !=
'}')
357 return Error::InvalidArgumentIndex;
360 if (pos < source.size() && source[pos] ==
':')
363 error = ParseFormatSpec(source, pos, field);
364 if (error != Error::None)
370 if (pos >= source.size())
372 return Error::UnexpectedEnd;
374 if (source[pos] !=
'}')
376 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 / 正在使用手动编号