@@ -3974,7 +3974,7 @@ _NODISCARD int _Measure_display_width(const basic_string_view<_CharT> _Value) {
39743974enum class _Fmt_tuple_type : uint8_t { _None, _Key_value, _No_brackets };
39753975
39763976template <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 {
39783978 int _Width = -1;
39793979 int _Dynamic_width_index = -1;
39803980 _Fmt_align _Alignment = _Fmt_align::_None;
@@ -4308,8 +4308,10 @@ public:
43084308 _Specs._Dynamic_width_index = _Verify_dynamic_arg_index_in_range(_Arg_id);
43094309 }
43104310
4311- private :
4311+ protected :
43124312 _Fill_align_and_width_specs<_CharT>& _Specs;
4313+
4314+ private:
43134315 basic_format_parse_context<_CharT>& _Parse_ctx;
43144316
43154317 _NODISCARD static constexpr int _Verify_dynamic_arg_index_in_range(const size_t _Idx) {
@@ -4365,6 +4367,253 @@ public:
43654367private:
43664368 _Fill_align_and_width_specs<_CharT> _Specs;
43674369};
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+ };
43684617#endif // _HAS_CXX23
43694618_STD_END
43704619
0 commit comments