Skip to content

Commit aed5ddf

Browse files
committed
[libc++][format] Implement format-string.
Implements the compile-time checking of the formatting arguments. Completes: - P2216 std::format improvements Reviewed By: #libc, ldionne Differential Revision: https://reviews.llvm.org/D121530
1 parent 338fd21 commit aed5ddf

21 files changed

+1152
-264
lines changed

libcxx/benchmarks/formatter_float.bench.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,17 +216,27 @@ struct FloatingPoint {
216216
void run(benchmark::State& state) const {
217217
std::array<F, 1000> data{Value<V::value>::template make_data<F>()};
218218
std::array<char, 20'000> output;
219-
std::string fmt{std::string("{:") + Alignment<A::value>::fmt + Precision<P::value>::fmt +
220-
Localization<L::value>::fmt + DisplayType<DT::value>::fmt + "}"};
221219

222220
while (state.KeepRunningBatch(1000))
223221
for (F value : data)
224-
benchmark::DoNotOptimize(std::format_to(output.begin(), fmt, value));
222+
benchmark::DoNotOptimize(std::format_to(output.begin(), std::string_view{fmt.data(), fmt.size()}, value));
225223
}
226224

227225
std::string name() const {
228226
return "FloatingPoint" + L::name() + DT::name() + T::name() + V::name() + A::name() + P::name();
229227
}
228+
229+
static constexpr std::string make_fmt() {
230+
return std::string("{:") + Alignment<A::value>::fmt + Precision<P::value>::fmt + Localization<L::value>::fmt +
231+
DisplayType<DT::value>::fmt + "}";
232+
}
233+
234+
static constexpr auto fmt = []() {
235+
constexpr size_t s = make_fmt().size();
236+
std::array<char, s> r;
237+
std::ranges::copy(make_fmt(), r.begin());
238+
return r;
239+
}();
230240
};
231241

232242
int main(int argc, char** argv) {

libcxx/docs/ReleaseNotes.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ New Features
7373
moved from the dylib to the header. This means the function no longer has a
7474
minimum deployment target.
7575

76+
- Implemented P2216R3 (std::format improvements). The format functions
77+
(``std::format``, ``std::format_to``, ``std::format_to_n``, and
78+
``std::formatted_size``) now validate the format string at compile time.
79+
When the format string is invalid this will make the code ill-formed instead
80+
of throwing an exception at run-time. (This does not affect the ``v``
81+
functions.)
82+
83+
7684
API Changes
7785
-----------
7886

libcxx/docs/Status/Cxx20Papers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@
196196
"`P2231R1 <https://wg21.link/P2231R1>`__","LWG","Missing constexpr in std::optional and std::variant","June 2021","|Partial| [#note-P2231]_","13.0"
197197
"`P2325R3 <https://wg21.link/P2325R3>`__","LWG","Views should not be required to be default constructible","June 2021","|In progress|",""
198198
"`P2210R2 <https://wg21.link/P2210R2>`__","LWG",Superior String Splitting,"June 2021","",""
199-
"`P2216R3 <https://wg21.link/P2216R3>`__","LWG",std::format improvements,"June 2021","|Partial|",""
199+
"`P2216R3 <https://wg21.link/P2216R3>`__","LWG",std::format improvements,"June 2021","|Complete|","15.0"
200200
"`P2281R1 <https://wg21.link/P2281R1>`__","LWG",Clarifying range adaptor objects,"June 2021","|Complete|","14.0"
201201
"`P2328R1 <https://wg21.link/P2328R1>`__","LWG",join_view should join all views of ranges,"June 2021","",""
202202
"`P2367R0 <https://wg21.link/P2367R0>`__","LWG",Remove misuses of list-initialization from Clause 24,"June 2021","",""

libcxx/include/__format/parser_std_format_spec.h

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -252,25 +252,21 @@ class _LIBCPP_TYPE_VIS __parser_width {
252252
/** Determines whether the value stored is a width or an arg-id. */
253253
uint32_t __width_as_arg : 1 {0};
254254

255-
protected:
256255
/**
257-
* Does the supplied std-format-spec contain a width field?
256+
* Does the supplied width field contain an arg-id?
258257
*
259-
* When the field isn't present there's no padding required. This can be used
260-
* to optimize the formatting.
258+
* If @c true the formatter needs to call @ref __substitute_width_arg_id.
261259
*/
262-
constexpr bool __has_width_field() const noexcept {
263-
return __width_as_arg || __width;
264-
}
260+
constexpr bool __width_needs_substitution() const noexcept { return __width_as_arg; }
265261

262+
protected:
266263
/**
267-
* Does the supplied width field contain an arg-id?
264+
* Does the supplied std-format-spec contain a width field?
268265
*
269-
* If @c true the formatter needs to call @ref __substitute_width_arg_id.
266+
* When the field isn't present there's no padding required. This can be used
267+
* to optimize the formatting.
270268
*/
271-
constexpr bool __width_needs_substitution() const noexcept {
272-
return __width_as_arg;
273-
}
269+
constexpr bool __has_width_field() const noexcept { return __width_as_arg || __width; }
274270

275271
template <class _CharT>
276272
_LIBCPP_HIDE_FROM_ABI constexpr const _CharT*
@@ -327,6 +323,15 @@ class _LIBCPP_TYPE_VIS __parser_precision {
327323
*/
328324
uint32_t __precision_as_arg : 1 {1};
329325

326+
/**
327+
* Does the supplied precision field contain an arg-id?
328+
*
329+
* If @c true the formatter needs to call @ref __substitute_precision_arg_id.
330+
*/
331+
constexpr bool __precision_needs_substitution() const noexcept {
332+
return __precision_as_arg && __precision != __format::__number_max;
333+
}
334+
330335
protected:
331336
/**
332337
* Does the supplied std-format-spec contain a precision field?
@@ -340,15 +345,6 @@ class _LIBCPP_TYPE_VIS __parser_precision {
340345
__precision != __format::__number_max; // The arg-id is valid?
341346
}
342347

343-
/**
344-
* Does the supplied precision field contain an arg-id?
345-
*
346-
* If @c true the formatter needs to call @ref __substitute_precision_arg_id.
347-
*/
348-
constexpr bool __precision_needs_substitution() const noexcept {
349-
return __precision_as_arg && __precision != __format::__number_max;
350-
}
351-
352348
template <class _CharT>
353349
_LIBCPP_HIDE_FROM_ABI constexpr const _CharT*
354350
__parse(const _CharT* __begin, const _CharT* __end, auto& __parse_ctx) {

0 commit comments

Comments
 (0)