@@ -3974,7 +3974,7 @@ _NODISCARD int _Measure_display_width(const basic_string_view<_CharT> _Value) {
3974
3974
enum class _Fmt_tuple_type : uint8_t { _None, _Key_value, _No_brackets };
3975
3975
3976
3976
template <class _CharT>
3977
- struct _Fill_align_and_width_specs { // used by pair, tuple, thread::id, and stacktrace_entry formatters
3977
+ struct _Fill_align_and_width_specs {
3978
3978
int _Width = -1;
3979
3979
int _Dynamic_width_index = -1;
3980
3980
_Fmt_align _Alignment = _Fmt_align::_None;
@@ -4308,8 +4308,10 @@ public:
4308
4308
_Specs._Dynamic_width_index = _Verify_dynamic_arg_index_in_range(_Arg_id);
4309
4309
}
4310
4310
4311
- private:
4311
+ protected:
4312
4312
_Fill_align_and_width_specs<_CharT>& _Specs;
4313
+
4314
+ private:
4313
4315
basic_format_parse_context<_CharT>& _Parse_ctx;
4314
4316
4315
4317
_NODISCARD static constexpr int _Verify_dynamic_arg_index_in_range(const size_t _Idx) {
@@ -4365,6 +4367,253 @@ public:
4365
4367
private:
4366
4368
_Fill_align_and_width_specs<_CharT> _Specs;
4367
4369
};
4370
+
4371
+ template <class _CharT>
4372
+ struct _Range_specs : _Fill_align_and_width_specs<_CharT> {
4373
+ bool _No_brackets = false;
4374
+ char _Type = '\0';
4375
+ };
4376
+
4377
+ template <class _CharT>
4378
+ class _Range_specs_setter : public _Fill_align_and_width_specs_setter<_CharT> {
4379
+ public:
4380
+ constexpr explicit _Range_specs_setter(
4381
+ _Range_specs<_CharT>& _Specs_, basic_format_parse_context<_CharT>& _Parse_ctx_)
4382
+ : _Fill_align_and_width_specs_setter<_CharT>(_Specs_, _Parse_ctx_) {}
4383
+
4384
+ constexpr void _On_no_brackets() {
4385
+ static_cast<_Range_specs<_CharT>&>(this->_Specs)._No_brackets = true;
4386
+ }
4387
+
4388
+ constexpr void _On_type(const _CharT _Type) {
4389
+ _STL_INTERNAL_CHECK(_Type == 'm' || _Type == 's' || _Type == '?');
4390
+ static_cast<_Range_specs<_CharT>&>(this->_Specs)._Type = static_cast<char>(_Type);
4391
+ }
4392
+ };
4393
+
4394
+ template <class _CharT>
4395
+ _NODISCARD constexpr const _CharT* _Parse_range_specs(
4396
+ const _CharT* _Begin, const _CharT* const _End, _Range_specs_setter<_CharT>& _Callbacks) {
4397
+ if (_Begin == _End || *_Begin == '}' || *_Begin == ':') {
4398
+ return _Begin;
4399
+ }
4400
+
4401
+ _Begin = _Parse_align(_Begin, _End, _Callbacks);
4402
+ if (_Begin == _End) {
4403
+ return _Begin;
4404
+ }
4405
+
4406
+ _Begin = _Parse_width(_Begin, _End, _Callbacks);
4407
+ if (_Begin == _End) {
4408
+ return _Begin;
4409
+ }
4410
+
4411
+ if (*_Begin == 'n') {
4412
+ _Callbacks._On_no_brackets();
4413
+ if (++_Begin == _End) {
4414
+ return _Begin;
4415
+ }
4416
+ }
4417
+
4418
+ switch (const _CharT _Maybe_type = *_Begin) {
4419
+ case '?':
4420
+ if (++_Begin == _End || *_Begin != 's') {
4421
+ _Throw_format_error("Invalid range-type '?'; was '?s' intended?");
4422
+ }
4423
+ [[fallthrough]];
4424
+ case 'm':
4425
+ case 's':
4426
+ _Callbacks._On_type(_Maybe_type);
4427
+ ++_Begin;
4428
+ break;
4429
+ }
4430
+
4431
+ return _Begin;
4432
+ }
4433
+
4434
+ _EXPORT_STD template <class _Ty, class _CharT = char>
4435
+ requires same_as<remove_cvref_t<_Ty>, _Ty> && formattable<_Ty, _CharT>
4436
+ class range_formatter {
4437
+ private:
4438
+ formatter<_Ty, _CharT> _Underlying;
4439
+ basic_string_view<_CharT> _Separator = _STATICALLY_WIDEN(_CharT, ", ");
4440
+ basic_string_view<_CharT> _Opening_bracket = _STATICALLY_WIDEN(_CharT, "[");
4441
+ basic_string_view<_CharT> _Closing_bracket = _STATICALLY_WIDEN(_CharT, "]");
4442
+ _Range_specs<_CharT> _Specs;
4443
+
4444
+ public:
4445
+ constexpr void set_separator(basic_string_view<_CharT> _Sep) noexcept {
4446
+ _Separator = _Sep;
4447
+ }
4448
+
4449
+ constexpr void set_brackets(basic_string_view<_CharT> _Opening, basic_string_view<_CharT> _Closing) noexcept {
4450
+ _Opening_bracket = _Opening;
4451
+ _Closing_bracket = _Closing;
4452
+ }
4453
+
4454
+ _NODISCARD constexpr formatter<_Ty, _CharT>& underlying() noexcept {
4455
+ return _Underlying;
4456
+ }
4457
+
4458
+ _NODISCARD constexpr const formatter<_Ty, _CharT>& underlying() const noexcept {
4459
+ return _Underlying;
4460
+ }
4461
+
4462
+ template <class _ParseContext>
4463
+ constexpr _ParseContext::iterator parse(_ParseContext& _Ctx) {
4464
+ _Range_specs_setter<_CharT> _Callback{_Specs, _Ctx};
4465
+ auto _It = _STD _Parse_range_specs(_Ctx._Unchecked_begin(), _Ctx._Unchecked_end(), _Callback);
4466
+
4467
+ _Ctx.advance_to(_Ctx.begin() + (_It - _Ctx._Unchecked_begin()));
4468
+ bool _Has_underlying_spec = false;
4469
+ if (_It != _Ctx._Unchecked_end()) {
4470
+ if (*_It == ':') {
4471
+ _Has_underlying_spec = true;
4472
+ _Ctx.advance_to(_Ctx.begin() + 1);
4473
+ } else if (*_It != '}') {
4474
+ _Throw_format_error("Invalid range-format-spec.");
4475
+ }
4476
+ }
4477
+
4478
+ _It = _Underlying.parse(_Ctx)._Unwrapped();
4479
+ if (_It != _Ctx._Unchecked_end() && *_It != '}') {
4480
+ _Throw_format_error("Missing '}' in format string.");
4481
+ }
4482
+
4483
+ switch (_Specs._Type) {
4484
+ case 'm':
4485
+ if constexpr (_Is_two_tuple<_Ty>) {
4486
+ set_brackets(_STATICALLY_WIDEN(_CharT, "{"), _STATICALLY_WIDEN(_CharT, "}"));
4487
+ set_separator(_STATICALLY_WIDEN(_CharT, ", "));
4488
+ _Underlying.set_brackets({}, {});
4489
+ _Underlying.set_separator(_STATICALLY_WIDEN(_CharT, ": "));
4490
+ } else {
4491
+ _Throw_format_error("Range-type 'm' requires type T to be a pair or a 2-element tuple.");
4492
+ }
4493
+ [[fallthrough]];
4494
+
4495
+ case '\0':
4496
+ if constexpr (requires { _Underlying.set_debug_format(); }) {
4497
+ if (!_Has_underlying_spec) {
4498
+ _Underlying.set_debug_format();
4499
+ }
4500
+ }
4501
+ break;
4502
+
4503
+ case 's':
4504
+ case '?':
4505
+ if constexpr (same_as<_Ty, _CharT>) {
4506
+ if (_Specs._No_brackets) {
4507
+ _Throw_format_error("Range-types 's' and '?s' cannot be combined with the 'n' option.");
4508
+ } else if (_Has_underlying_spec) {
4509
+ _Throw_format_error("Range-types 's' and '?s' cannot be combined with a range-underlying-spec.");
4510
+ }
4511
+ } else {
4512
+ _Throw_format_error("Range-types 's' and '?s' require type T to be charT.");
4513
+ }
4514
+
4515
+ break;
4516
+ }
4517
+
4518
+ if (_Specs._No_brackets) {
4519
+ set_brackets({}, {});
4520
+ }
4521
+
4522
+ return _Ctx.begin() + (_It - _Ctx._Unchecked_begin());
4523
+ }
4524
+
4525
+ template <_RANGES input_range _Range, class _FormatContext>
4526
+ requires formattable<_RANGES range_reference_t<_Range>, _CharT>
4527
+ && same_as<remove_cvref_t<_RANGES range_reference_t<_Range>>, _Ty>
4528
+ _FormatContext::iterator format(_Range&& _Rng, _FormatContext& _Ctx) const {
4529
+ return _Format(_STD forward<_Range>(_Rng), _Ctx);
4530
+ }
4531
+
4532
+ private:
4533
+ template <_RANGES input_range _Range, class _FormatContext>
4534
+ _FormatContext::iterator _Format(_Range&&, _FormatContext&) const {
4535
+ _Throw_format_error("Unsupported 'basic_format_context'.");
4536
+ }
4537
+
4538
+ template <_RANGES input_range _Range, class _FormatContext>
4539
+ requires _Is_specialization_v<typename _FormatContext::iterator, back_insert_iterator>
4540
+ && derived_from<typename _FormatContext::iterator::container_type, _Fmt_buffer<_CharT>>
4541
+ _FormatContext::iterator _Format(_Range&& _Rng, _FormatContext& _Ctx) const {
4542
+ auto _Format_specs = _Specs;
4543
+ if (_Specs._Dynamic_width_index >= 0) {
4544
+ _Format_specs._Width =
4545
+ _STD _Get_dynamic_specs<_Width_checker>(_Ctx.arg(static_cast<size_t>(_Specs._Dynamic_width_index)));
4546
+ }
4547
+
4548
+ basic_string<_CharT> _Buffer;
4549
+ {
4550
+ _Fmt_iterator_buffer<back_insert_iterator<basic_string<_CharT>>, _CharT> _Fmt_buf(
4551
+ back_insert_iterator{_Buffer});
4552
+ using _Inserter = back_insert_iterator<_Fmt_buffer<_CharT>>;
4553
+ auto _Nested_context = basic_format_context<_Inserter, _CharT>::_Make_from(
4554
+ _Inserter{_Fmt_buf}, _Ctx._Get_args(), _Ctx._Get_lazy_locale());
4555
+
4556
+ if constexpr (same_as<_Ty, _CharT>) {
4557
+ if (_Specs._Type == 's' || _Specs._Type == '?') {
4558
+ _Format_as_string(_STD forward<_Range>(_Rng), _Nested_context, _Specs._Type == '?');
4559
+ } else {
4560
+ _Format_as_sequence(_STD forward<_Range>(_Rng), _Nested_context);
4561
+ }
4562
+ } else {
4563
+ _Format_as_sequence(_STD forward<_Range>(_Rng), _Nested_context);
4564
+ }
4565
+ }
4566
+
4567
+ const int _Width = _Measure_display_width<_CharT>(_Buffer);
4568
+ return _STD _Write_aligned(
4569
+ _Ctx.out(), _Width, _Format_specs, _Fmt_align::_Left, [&](_FormatContext::iterator _Out) {
4570
+ return _STD _Fmt_write(_STD move(_Out), basic_string_view{_Buffer});
4571
+ });
4572
+ }
4573
+
4574
+ template <_RANGES input_range _Range, class _FormatContext>
4575
+ void _Format_as_sequence(_Range&& _Rng, _FormatContext& _Ctx) const {
4576
+ _Ctx.advance_to(_STD _Fmt_write(_Ctx.out(), _Opening_bracket));
4577
+ bool _Separate = false;
4578
+ for (auto&& _Elem : _Rng) {
4579
+ if (_Separate) {
4580
+ _Ctx.advance_to(_STD _Fmt_write(_Ctx.out(), _Separator));
4581
+ }
4582
+
4583
+ _Separate = true;
4584
+ _Ctx.advance_to(_Underlying.format(_Elem, _Ctx));
4585
+ }
4586
+
4587
+ (void) _STD _Fmt_write(_Ctx.out(), _Closing_bracket);
4588
+ }
4589
+
4590
+ template <_RANGES input_range _Range, class _FormatContext>
4591
+ void _Format_as_string(_Range&& _Rng, _FormatContext& _Ctx, const bool _Debug) const {
4592
+ if constexpr (_RANGES contiguous_range<_Range>) {
4593
+ const auto _Size = _STD _To_unsigned_like(_RANGES distance(_Rng));
4594
+
4595
+ if (!_STD in_range<size_t>(_Size)) [[unlikely]] {
4596
+ _Throw_format_error("Formatted range is too long.");
4597
+ }
4598
+
4599
+ formatter<basic_string_view<_CharT>, _CharT> _String_view_formatter;
4600
+ if (_Debug) {
4601
+ _String_view_formatter.set_debug_format();
4602
+ }
4603
+
4604
+ const basic_string_view<_CharT> _Str(_STD to_address(_RANGES begin(_Rng)), static_cast<size_t>(_Size));
4605
+ _String_view_formatter.format(_Str, _Ctx);
4606
+ } else {
4607
+ using _String = basic_string<_CharT>;
4608
+ formatter<_String, _CharT> _String_formatter;
4609
+ if (_Debug) {
4610
+ _String_formatter.set_debug_format();
4611
+ }
4612
+
4613
+ _String_formatter.format(_String{from_range, _Rng}, _Ctx);
4614
+ }
4615
+ }
4616
+ };
4368
4617
#endif // _HAS_CXX23
4369
4618
_STD_END
4370
4619
0 commit comments