@@ -4247,6 +4247,150 @@ private:
4247
4247
}
4248
4248
};
4249
4249
4250
+ template <class _Rng, class _CharT>
4251
+ concept _Const_formattable_range =
4252
+ _RANGES input_range<const _Rng> && formattable<_RANGES range_reference_t<const _Rng>, _CharT>;
4253
+
4254
+ template <class _Rng, class _CharT>
4255
+ using _Fmt_maybe_const = conditional_t<_Const_formattable_range<_Rng, _CharT>, const _Rng, _Rng>;
4256
+
4257
+ template <range_format _Kind, class _Rng, class _CharT>
4258
+ struct _Range_default_formatter;
4259
+
4260
+ template <_RANGES input_range _Rng, class _CharT>
4261
+ struct _Range_default_formatter<range_format::sequence, _Rng, _CharT> {
4262
+ private:
4263
+ using _Range_type = _Fmt_maybe_const<_Rng, _CharT>;
4264
+
4265
+ range_formatter<remove_cvref_t<_RANGES range_reference_t<_Range_type>>, _CharT> _Underlying;
4266
+
4267
+ public:
4268
+ constexpr void set_separator(const basic_string_view<_CharT> _Sep) noexcept {
4269
+ _Underlying.set_separator(_Sep);
4270
+ }
4271
+
4272
+ constexpr void set_brackets(
4273
+ const basic_string_view<_CharT> _Opening, const basic_string_view<_CharT> _Closing) noexcept {
4274
+ _Underlying.set_brackets(_Opening, _Closing);
4275
+ }
4276
+
4277
+ template <class _ParseContext>
4278
+ constexpr _ParseContext::iterator parse(_ParseContext& _Ctx) {
4279
+ return _Underlying.parse(_Ctx);
4280
+ }
4281
+
4282
+ template <class _FormatContext>
4283
+ _FormatContext::iterator format(_Range_type& _Elems, _FormatContext& _Ctx) const {
4284
+ return _Underlying.format(_Elems, _Ctx);
4285
+ }
4286
+ };
4287
+
4288
+ template <_RANGES input_range _Rng, class _CharT>
4289
+ struct _Range_default_formatter<range_format::map, _Rng, _CharT> {
4290
+ private:
4291
+ using _Map_type = _Fmt_maybe_const<_Rng, _CharT>;
4292
+ using _Element_type = remove_cvref_t<_RANGES range_reference_t<_Map_type>>;
4293
+
4294
+ range_formatter<_Element_type, _CharT> _Underlying;
4295
+
4296
+ public:
4297
+ constexpr _Range_default_formatter() noexcept(
4298
+ is_nothrow_default_constructible_v<range_formatter<_Element_type, _CharT>>) /* strengthened */ {
4299
+ static_assert(_Is_two_tuple<_Element_type>, "the element type of the formatted range must be either pair<T, U> "
4300
+ "or tuple<T, U> (N4981 [format.range.fmtmap]/1)");
4301
+
4302
+ _Underlying.set_brackets(_STATICALLY_WIDEN(_CharT, "{"), _STATICALLY_WIDEN(_CharT, "}"));
4303
+ _Underlying.underlying().set_brackets({}, {});
4304
+ _Underlying.underlying().set_separator(_STATICALLY_WIDEN(_CharT, ": "));
4305
+ }
4306
+
4307
+ template <class _ParseContext>
4308
+ constexpr _ParseContext::iterator parse(_ParseContext& _Ctx) {
4309
+ return _Underlying.parse(_Ctx);
4310
+ }
4311
+
4312
+ template <class _FormatContext>
4313
+ _FormatContext::iterator format(_Map_type& _Rx, _FormatContext& _Ctx) const {
4314
+ return _Underlying.format(_Rx, _Ctx);
4315
+ }
4316
+ };
4317
+
4318
+ template <_RANGES input_range _Rng, class _CharT>
4319
+ struct _Range_default_formatter<range_format::set, _Rng, _CharT> {
4320
+ private:
4321
+ using _Set_type = _Fmt_maybe_const<_Rng, _CharT>; // exposition only
4322
+ range_formatter<remove_cvref_t<_RANGES range_reference_t<_Set_type>>, _CharT> _Underlying;
4323
+
4324
+ public:
4325
+ constexpr _Range_default_formatter() noexcept(is_nothrow_default_constructible_v<
4326
+ range_formatter<remove_cvref_t<_RANGES range_reference_t<_Set_type>>, _CharT>>) /* strengthened */ {
4327
+ _Underlying.set_brackets(_STATICALLY_WIDEN(_CharT, "{"), _STATICALLY_WIDEN(_CharT, "}"));
4328
+ }
4329
+
4330
+ template <class _ParseContext>
4331
+ constexpr _ParseContext::iterator parse(_ParseContext& _Ctx) {
4332
+ return _Underlying.parse(_Ctx);
4333
+ }
4334
+
4335
+ template <class _FormatContext>
4336
+ _FormatContext::iterator format(_Set_type& _Rx, _FormatContext& _Ctx) const {
4337
+ return _Underlying.format(_Rx, _Ctx);
4338
+ }
4339
+ };
4340
+
4341
+ template <range_format _Kind, _RANGES input_range _Rng, class _CharT>
4342
+ requires (_Kind == range_format::string || _Kind == range_format::debug_string)
4343
+ struct _Range_default_formatter<_Kind, _Rng, _CharT> {
4344
+ private:
4345
+ static_assert(is_same_v<remove_cvref_t<_RANGES range_reference_t<_Rng>>, _CharT>,
4346
+ "the element type of the formatted range must be the character type used in formatting "
4347
+ "(N4981 [format.range.fmtstr]/1)");
4348
+
4349
+ using _Range_type = _Maybe_const<_RANGES input_range<const _Rng>, _Rng>;
4350
+
4351
+ formatter<basic_string_view<_CharT>, _CharT> _Underlying; // avoid copy the string if possible
4352
+
4353
+ public:
4354
+ template <class _ParseContext>
4355
+ constexpr _ParseContext::iterator parse(_ParseContext& _Ctx) {
4356
+ auto _Iter = _Underlying.parse(_Ctx);
4357
+ if constexpr (_Kind == range_format::debug_string) {
4358
+ _Underlying.set_debug_format();
4359
+ }
4360
+ return _Iter;
4361
+ }
4362
+
4363
+ template <class _FormatContext>
4364
+ _FormatContext::iterator format(_Range_type& _Rx, _FormatContext& _Ctx) const {
4365
+ if constexpr (_RANGES contiguous_range<_Range_type>) {
4366
+ const auto _Size = _STD _To_unsigned_like(_RANGES distance(_Rx));
4367
+
4368
+ if (!_STD in_range<size_t>(_Size)) [[unlikely]] {
4369
+ _Throw_format_error("Formatted range is too long.");
4370
+ }
4371
+
4372
+ const basic_string_view<_CharT> _Str(_STD to_address(_RANGES begin(_Rx)), static_cast<size_t>(_Size));
4373
+ return _Underlying.format(_Str, _Ctx);
4374
+ } else {
4375
+ return _Underlying.format(basic_string<_CharT>{from_range, _Rx}, _Ctx);
4376
+ }
4377
+ }
4378
+ };
4379
+
4380
+ // the deleted default constructor makes it "disabled" as per N4981 [format.formatter.spec]/5
4381
+
4382
+ template <_RANGES input_range _Rng, _Format_supported_charT _CharT>
4383
+ requires _Formatting_enabled_range<_Rng>
4384
+ struct formatter<_Rng, _CharT> {
4385
+ formatter() = delete;
4386
+ formatter(const formatter&) = delete;
4387
+ formatter& operator=(const formatter&) = delete;
4388
+ };
4389
+
4390
+ template <_RANGES input_range _Rng, _Format_supported_charT _CharT>
4391
+ requires _Formatting_enabled_range<_Rng> && formattable<_RANGES range_reference_t<_Rng>, _CharT>
4392
+ struct formatter<_Rng, _CharT> : _Range_default_formatter<format_kind<_Rng>, _Rng, _CharT> {};
4393
+
4250
4394
enum class _Fmt_tuple_type : uint8_t { _None, _Key_value, _No_brackets };
4251
4395
4252
4396
template <class _CharT, bool _IsTwoTuple>
@@ -4497,6 +4641,24 @@ public:
4497
4641
}
4498
4642
};
4499
4643
4644
+ // specializations for tuple-like types that are input ranges and not formattable as tuples
4645
+
4646
+ template <_Format_supported_charT _CharT, class _Ty1, class _Ty2>
4647
+ requires (!formattable<_Ty1, _CharT> || !formattable<_Ty2, _CharT>)
4648
+ // TRANSITION, clang-format, () should be redundant
4649
+ && (_RANGES input_range<pair<_Ty1, _Ty2>>) && _Formatting_enabled_range<pair<_Ty1, _Ty2>>
4650
+ && formattable<_RANGES range_reference_t<pair<_Ty1, _Ty2>>, _CharT>
4651
+ struct _Tuple_formatter_base<pair<_Ty1, _Ty2>, _CharT>
4652
+ : _Range_default_formatter<format_kind<pair<_Ty1, _Ty2>>, pair<_Ty1, _Ty2>, _CharT> {};
4653
+
4654
+ template <_Format_supported_charT _CharT, class... _Types>
4655
+ requires ((!formattable<_Types, _CharT>) || ...)
4656
+ // TRANSITION, clang-format, () should be redundant
4657
+ && (_RANGES input_range<tuple<_Types...>>) && _Formatting_enabled_range<tuple<_Types...>>
4658
+ && formattable<_RANGES range_reference_t<tuple<_Types...>>, _CharT>
4659
+ struct _Tuple_formatter_base<tuple<_Types...>, _CharT>
4660
+ : _Range_default_formatter<format_kind<tuple<_Types...>>, tuple<_Types...>, _CharT> {};
4661
+
4500
4662
// Per LWG-3997, `_CharT` in library-provided `formatter` specializations is
4501
4663
// constrained to character types supported by `format`.
4502
4664
0 commit comments