@@ -28,45 +28,51 @@ template <std::size_t N> constexpr auto format_as(stdx::ct_string<N> const &s) {
2828 return std::string_view{s};
2929}
3030
31- template <std::size_t Begin, std::size_t End> struct format_span {
31+ template <stdx::ct_string Name, typename T, int Begin, int End = Begin - 1 >
32+ struct named_arg {
33+ using type = T;
34+ constexpr static auto name = Name;
3235 constexpr static auto begin = Begin;
3336 constexpr static auto end = End;
3437
38+ constexpr static std::integral_constant<bool , Begin >= End> is_runtime{};
39+
40+ template <int StringOffset, int ArgOffset>
41+ CONSTEVAL static auto apply_offset () {
42+ if constexpr (is_runtime) {
43+ return named_arg<Name, T, Begin + ArgOffset, End + ArgOffset>{};
44+ } else {
45+ return named_arg<Name, T, Begin + StringOffset,
46+ End + StringOffset>{};
47+ }
48+ }
49+
3550 private:
36- friend constexpr auto operator ==(format_span const &, format_span const &)
51+ friend constexpr auto operator ==(named_arg const &, named_arg const &)
3752 -> bool = default ;
3853};
3954
4055namespace detail {
41- template <std::size_t Offset> struct apply_span_offset_q {
42- template <typename Span>
43- using fn = format_span<Offset + Span::begin, Offset + Span::end>;
56+ template <std::size_t StringOffset, std::size_t ArgOffset>
57+ struct apply_span_offset_q {
58+ template <typename Arg>
59+ using fn = decltype (Arg::template apply_offset<StringOffset, ArgOffset>());
4460};
4561
46- template <std::size_t Offset , typename L>
62+ template <std::size_t StringOffset, std:: size_t ArgOffset , typename L>
4763using apply_offset =
48- boost::mp11::mp_transform_q<apply_span_offset_q<Offset>, L>;
64+ boost::mp11::mp_transform_q<apply_span_offset_q<StringOffset, ArgOffset>,
65+ L>;
4966} // namespace detail
5067
51- template <typename T = void > struct ct_format_arg {
52- using type_t = T;
53- friend constexpr auto operator ==(ct_format_arg const &,
54- ct_format_arg const &) -> bool = default ;
55- };
56-
57- template <typename Arg>
58- using is_compile_time_arg =
59- std::bool_constant<is_specialization_of<Arg, ct_format_arg>()>;
60-
61- template <typename Str, typename Args, typename Spans> struct format_result {
62- static_assert (Args::size() == boost::mp11::mp_size<Spans>::value);
63-
68+ template <typename Str, typename Args, typename NamedArgs>
69+ struct format_result {
6470 CONSTEVAL static auto ct_string_convertible ()
6571 -> std::bool_constant<Args::size() == 0>;
6672
6773 [[no_unique_address]] Str str;
6874 [[no_unique_address]] Args args{};
69- using spans_t = Spans ;
75+ using named_args_t = NamedArgs ;
7076
7177 friend constexpr auto operator +(format_result const &fr)
7278 requires (decltype (ct_string_convertible())::value)
@@ -85,17 +91,14 @@ template <typename Str, typename Args, typename Spans> struct format_result {
8591 format_result const &) -> bool = default ;
8692};
8793
88- template <typename Str, typename Args, typename Spans>
89- requires (boost::mp11::mp_all_of<Args, is_compile_time_arg>::value and
90- is_cx_value_v<Str>)
91- struct format_result <Str, Args, Spans> {
92- static_assert (Args::size() == boost::mp11::mp_size<Spans>::value);
93-
94+ template <typename Str, typename Args, typename NamedArgs>
95+ requires (Args::size() == 0 and is_cx_value_v<Str>)
96+ struct format_result <Str, Args, NamedArgs> {
9497 CONSTEVAL static auto ct_string_convertible () -> std::true_type;
9598
9699 [[no_unique_address]] Str str;
97100 [[no_unique_address]] Args args{};
98- using spans_t = Spans ;
101+ using named_args_t = NamedArgs ;
99102
100103 friend constexpr auto operator +(format_result const &fr) { return +fr.str ; }
101104
@@ -107,9 +110,10 @@ struct format_result<Str, Args, Spans> {
107110 format_result const &) -> bool = default ;
108111};
109112
110- template <typename Spans = type_list<>, typename Str, typename Args = tuple<>>
113+ template <typename NamedArgs = type_list<>, typename Str,
114+ typename Args = tuple<>>
111115constexpr auto make_format_result (Str s, Args args = {}) {
112- return format_result<Str, Args, Spans >{s, std::move (args)};
116+ return format_result<Str, Args, NamedArgs >{s, std::move (args)};
113117}
114118
115119inline namespace literals {
@@ -180,6 +184,50 @@ CONSTEVAL auto split_specifiers(std::string_view fmt)
180184 return splits;
181185}
182186
187+ template <ct_string S, std::size_t Start> CONSTEVAL auto extract_format1_str () {
188+ constexpr auto name_start = Start + 1 ;
189+ constexpr auto it = [] {
190+ for (auto i = S.value .cbegin () + name_start; i != S.value .cend (); ++i) {
191+ if (*i == ' :' ) {
192+ return i;
193+ }
194+ }
195+ return S.value .cend ();
196+ }();
197+ if constexpr (it == S.value .cend ()) {
198+ if constexpr (Start == S.size () - 2 ) {
199+ // no name, empty fmt spec e.g. "abc{}"
200+ return std::pair{S, ct_string{" " }};
201+ } else {
202+ // named arg, empty fmt spec, e.g. "abc{ghi}"
203+ constexpr auto suffix_start = S.size () - 1 ;
204+ constexpr auto prefix_size = name_start;
205+ constexpr auto name_size = suffix_start - name_start;
206+ constexpr auto suffix_size = 1 ;
207+
208+ return std::pair{
209+ ct_string<prefix_size + 1U >{S.value .cbegin (), prefix_size} +
210+ ct_string<suffix_size + 1U >{S.value .cbegin () + suffix_start,
211+ suffix_size},
212+ ct_string<name_size + 1U >{S.value .cbegin () + name_start,
213+ name_size}};
214+ }
215+ } else {
216+ // named arg, fmt spec, e.g. "abc{ghi:x}"
217+ constexpr auto suffix_start = it - S.value .cbegin ();
218+ constexpr auto prefix_size = name_start;
219+ constexpr auto name_size = suffix_start - name_start;
220+ constexpr auto suffix_size = S.size () - suffix_start;
221+
222+ return std::pair{
223+ ct_string<prefix_size + 1U >{S.value .cbegin (), prefix_size} +
224+ ct_string<suffix_size + 1U >{S.value .cbegin () + suffix_start,
225+ suffix_size},
226+ ct_string<name_size + 1U >{S.value .cbegin () + name_start,
227+ name_size}};
228+ }
229+ }
230+
183231template <typename T>
184232concept fmt_cx_value =
185233 is_cx_value_v<T> or requires (T t) { ct_string_from_type (t); };
@@ -226,23 +274,27 @@ CONSTEVAL auto arg_type(fmt_cx_value auto a) {
226274 }
227275}
228276
229- template <typename Str, typename Args, typename Spans , typename S>
230- constexpr auto operator +(format_result<Str, Args, Spans > r, S s) {
231- return make_format_result<Spans >(r.str + s, std::move (r.args ));
277+ template <typename Str, typename Args, typename NamedArgs , typename S>
278+ constexpr auto operator +(format_result<Str, Args, NamedArgs > r, S s) {
279+ return make_format_result<NamedArgs >(r.str + s, std::move (r.args ));
232280}
233281
234- template <typename S, typename Str, typename Args, typename Spans >
235- constexpr auto operator +(S s, format_result<Str, Args, Spans > r) {
236- return make_format_result<detail::apply_offset<s.size (), Spans >>(
282+ template <typename S, typename Str, typename Args, typename NamedArgs >
283+ constexpr auto operator +(S s, format_result<Str, Args, NamedArgs > r) {
284+ return make_format_result<detail::apply_offset<s.size (), 0 , NamedArgs >>(
237285 s + r.str , std::move (r.args ));
238286}
239287
240- template <typename Str1, typename Args1, typename Spans1, typename Str2,
241- typename Args2, typename Spans2>
242- constexpr auto operator +(format_result<Str1, Args1, Spans1> r1,
243- format_result<Str2, Args2, Spans2> r2) {
244- return make_format_result<boost::mp11::mp_append<
245- Spans1, detail::apply_offset<r1.str .size (), Spans2>>>(
288+ template <typename Str1, typename Args1, typename NamedArgs1, typename Str2,
289+ typename Args2, typename NamedArgs2>
290+ constexpr auto operator +(format_result<Str1, Args1, NamedArgs1> r1,
291+ format_result<Str2, Args2, NamedArgs2> r2) {
292+ using ShiftedNamedArgs2 =
293+ detail::apply_offset<r1.str .size (), boost::mp11::mp_size<Args1>::value,
294+ NamedArgs2>;
295+
296+ return make_format_result<
297+ boost::mp11::mp_append<NamedArgs1, ShiftedNamedArgs2>>(
246298 r1.str + r2.str ,
247299 stdx::tuple_cat (std::move (r1.args ), std::move (r2.args )));
248300}
@@ -278,35 +330,44 @@ CONSTEVAL auto perform_format(auto s, auto const &v) -> ct_string<N + 1> {
278330 return cts;
279331}
280332
281- template <ct_string Fmt, std::size_t Start, typename Arg>
333+ template <ct_string Fmt, ct_string Name, std::size_t Start, typename Arg>
282334constexpr auto format1 (Arg arg) {
283335 if constexpr (requires { arg_value (arg); }) {
284336 constexpr auto fmtstr = STDX_FMT_COMPILE (Fmt);
285337 constexpr auto a = arg_value (arg);
286- if constexpr (is_specialization_of_v< std::remove_cv_t <decltype (a)>,
287- format_result>) {
338+ using a_t = std::remove_cv_t <decltype (a)>;
339+ if constexpr (is_specialization_of_v< a_t , format_result>) {
288340 constexpr auto s = convert_input (a.str );
289341 constexpr auto sz = fmt::formatted_size (fmtstr, s);
290342 constexpr auto cts = perform_format<sz>(fmtstr, s);
291- using Spans = typename std::remove_cvref_t <decltype (a)>::spans_t ;
292- return make_format_result<detail::apply_offset<Start, Spans>>(
293- cts_t <cts>{}, a.args );
343+ using shifted_named_args_t =
344+ detail::apply_offset<Start, 0 , typename a_t ::named_args_t >;
345+ return make_format_result<shifted_named_args_t >(cts_t <cts>{},
346+ a.args );
294347 } else {
295- using arg_t = stdx::remove_cvref_t <decltype (arg_type (arg))>;
296348 constexpr auto sz = fmt::formatted_size (fmtstr, a);
297349 constexpr auto cts = perform_format<sz>(fmtstr, a);
298- using Spans = type_list<format_span<Start, sz>>;
299- return make_format_result<Spans>(cts_t <cts>{},
300- tuple{ct_format_arg<arg_t >{}});
350+ if constexpr (not Name.empty ()) {
351+ using name_info_t = named_arg<Name, a_t , Start, sz>;
352+ return make_format_result<type_list<name_info_t >>(cts_t <cts>{});
353+ } else {
354+ return make_format_result (cts_t <cts>{});
355+ }
301356 }
302357 } else if constexpr (is_specialization_of_v<Arg, format_result>) {
303- auto const sub_result = format1<Fmt, Start>(arg.str );
304- using Spans = typename Arg::spans_t ;
305- return make_format_result<detail::apply_offset<Start, Spans>>(
306- sub_result.str , std::move (arg).args );
358+ auto const sub_result = format1<Fmt, " " , Start>(arg.str );
359+ using shifted_named_args_t =
360+ detail::apply_offset<Start, 0 , typename Arg::named_args_t >;
361+ return make_format_result<shifted_named_args_t >(sub_result.str ,
362+ std::move (arg).args );
307363 } else {
308- using Spans = type_list<format_span<Start, Fmt.size ()>>;
309- return make_format_result<Spans>(cts_t <Fmt>{}, tuple{std::move (arg)});
364+ if constexpr (not Name.empty ()) {
365+ using name_info_t = named_arg<Name, Arg, 0 >;
366+ return make_format_result<type_list<name_info_t >>(
367+ cts_t <Fmt>{}, tuple{std::move (arg)});
368+ } else {
369+ return make_format_result (cts_t <Fmt>{}, tuple{std::move (arg)});
370+ }
310371 }
311372}
312373
@@ -355,9 +416,12 @@ constexpr auto ct_format = [](auto &&...args) {
355416 " specifiers and arguments." );
356417
357418 [[maybe_unused]] auto const format1 = []<std::size_t I>(auto &&arg) {
358- constexpr auto cts = detail::to_ct_string<data::splits[I].view .size ()>(
359- data::splits[I].view );
360- return detail::format1<cts, data::splits[I].start >(FWD (arg));
419+ constexpr auto fmt = detail::extract_format1_str<
420+ detail::to_ct_string<data::splits[I].view .size ()>(
421+ data::splits[I].view ),
422+ data::splits[I].start >();
423+ return detail::format1<fmt.first , fmt.second , data::splits[I].start >(
424+ FWD (arg));
361425 };
362426
363427 auto result = [&]<std::size_t ... Is>(std::index_sequence<Is...>,
@@ -366,8 +430,9 @@ constexpr auto ct_format = [](auto &&...args) {
366430 ... + make_format_result (cts_t <data::last_cts>{}));
367431 }(std::make_index_sequence<data::N>{}, FWD (args)...);
368432 constexpr auto str = detail::convert_output<result.str .value , Output>();
369- using Spans = typename std::remove_cvref_t <decltype (result)>::spans_t ;
370- return make_format_result<Spans>(str, std::move (result).args );
433+ using NamedArgs =
434+ typename std::remove_cvref_t <decltype (result)>::named_args_t ;
435+ return make_format_result<NamedArgs>(str, std::move (result).args );
371436};
372437
373438template <ct_string Fmt>
0 commit comments