1313#include < stdx/type_traits.hpp>
1414#include < stdx/utility.hpp>
1515
16+ #include < boost/mp11/algorithm.hpp>
17+
1618#include < algorithm>
1719#include < array>
1820#include < cstddef>
@@ -29,22 +31,45 @@ template <std::size_t N> constexpr auto format_as(stdx::ct_string<N> const &s) {
2931 return std::string_view{s};
3032}
3133
32- struct format_span {
33- std:: size_t begin_idx ;
34- std:: size_t end_idx ;
34+ template <std:: size_t Begin, std:: size_t End> struct format_span {
35+ constexpr static auto begin = Begin ;
36+ constexpr static auto end = End ;
3537
3638 private:
3739 friend constexpr auto operator ==(format_span const &, format_span const &)
3840 -> bool = default ;
3941};
4042
41- template <typename Str, typename Spans, typename Args> struct format_result {
43+ namespace detail {
44+ template <std::size_t Offset> struct apply_span_offset_q {
45+ template <typename Span>
46+ using fn = format_span<Offset + Span::begin, Offset + Span::end>;
47+ };
48+
49+ template <std::size_t Offset, typename L>
50+ using apply_offset =
51+ boost::mp11::mp_transform_q<apply_span_offset_q<Offset>, L>;
52+ } // namespace detail
53+
54+ template <typename T = void > struct ct_format_arg {
55+ using type_t = T;
56+ friend constexpr auto operator ==(ct_format_arg const &,
57+ ct_format_arg const &) -> bool = default ;
58+ };
59+
60+ template <typename Arg>
61+ using is_compile_time_arg =
62+ std::bool_constant<is_specialization_of<Arg, ct_format_arg>()>;
63+
64+ template <typename Str, typename Args, typename Spans> struct format_result {
65+ static_assert (Args::size() == boost::mp11::mp_size<Spans>::value);
66+
4267 CONSTEVAL static auto ct_string_convertible ()
4368 -> std::bool_constant<Args::size() == 0>;
4469
4570 [[no_unique_address]] Str str;
46- [[no_unique_address]] Spans spans{};
4771 [[no_unique_address]] Args args{};
72+ using spans_t = Spans;
4873
4974 friend constexpr auto operator +(format_result const &fr)
5075 requires (decltype (ct_string_convertible())::value)
@@ -63,14 +88,17 @@ template <typename Str, typename Spans, typename Args> struct format_result {
6388 format_result const &) -> bool = default ;
6489};
6590
66- template <typename Str, typename Spans, typename Args>
67- requires (Args::size() == 0 and is_cx_value_v<Str>)
68- struct format_result <Str, Spans, Args> {
91+ template <typename Str, typename Args, typename Spans>
92+ requires (boost::mp11::mp_all_of<Args, is_compile_time_arg>::value and
93+ is_cx_value_v<Str>)
94+ struct format_result <Str, Args, Spans> {
95+ static_assert (Args::size() == boost::mp11::mp_size<Spans>::value);
96+
6997 CONSTEVAL static auto ct_string_convertible () -> std::true_type;
7098
7199 [[no_unique_address]] Str str;
72- [[no_unique_address]] Spans spans{};
73100 [[no_unique_address]] Args args{};
101+ using spans_t = Spans;
74102
75103 friend constexpr auto operator +(format_result const &fr) { return +fr.str ; }
76104
@@ -82,17 +110,15 @@ struct format_result<Str, Spans, Args> {
82110 format_result const &) -> bool = default ;
83111};
84112
85- template <typename Str, typename Spans, typename Args>
86- format_result (Str, Spans, Args) -> format_result<Str, Spans, Args>;
87- template <typename Str, typename Spans>
88- format_result (Str, Spans) -> format_result<Str, Spans, tuple<>>;
89- template <typename Str>
90- format_result (Str) -> format_result<Str, tuple<>, tuple<>>;
113+ template <typename Spans = type_list<>, typename Str, typename Args = tuple<>>
114+ constexpr auto make_format_result (Str s, Args args = {}) {
115+ return format_result<Str, Args, Spans>{s, args};
116+ }
91117
92118inline namespace literals {
93119inline namespace ct_string_literals {
94120template <ct_string S> CONSTEVAL_UDL auto operator " " _fmt_res() {
95- return format_result{ cts_t <S>{}} ;
121+ return make_format_result ( cts_t <S>{}) ;
96122}
97123} // namespace ct_string_literals
98124} // namespace literals
@@ -177,46 +203,50 @@ template <typename T> CONSTEVAL auto arg_value(type_identity<T>) {
177203template <ct_string S> CONSTEVAL auto arg_value (cts_t <S>) { return S; }
178204
179205CONSTEVAL auto arg_value (fmt_cx_value auto a) {
180- if constexpr (requires { ct_string_from_type (a); }) {
206+ if constexpr (is_specialization_of_v<decltype (a), format_result>) {
207+ return a;
208+ } else if constexpr (requires { arg_value (a ()); }) {
209+ return arg_value (a ());
210+ } else if constexpr (requires { ct_string_from_type (a); }) {
181211 return ct_string_from_type (a);
182212 } else if constexpr (std::is_enum_v<decltype (a ())>) {
183213 return enum_as_string<a ()>();
184- } else if constexpr (requires { arg_value (a ()); }) {
185- return arg_value (a ());
186214 } else {
187215 return a ();
188216 }
189217}
190218
191- template <typename T, typename U, typename V, typename S>
192- constexpr auto operator +(format_result<T, U, V> r, S s) {
193- return format_result{r.str + s, r.spans , r.args };
219+ template <typename T> CONSTEVAL auto arg_type (T) -> T;
220+
221+ template <typename T, T V>
222+ CONSTEVAL auto arg_type (std::integral_constant<T, V>) -> T;
223+
224+ CONSTEVAL auto arg_type (fmt_cx_value auto a) {
225+ if constexpr (requires { ct_string_from_type (a); }) {
226+ return ct_string_from_type (a);
227+ } else {
228+ return a ();
229+ }
230+ }
231+
232+ template <typename Str, typename Args, typename Spans, typename S>
233+ constexpr auto operator +(format_result<Str, Args, Spans> r, S s) {
234+ return make_format_result<Spans>(r.str + s, r.args );
194235}
195236
196- template <typename S, typename T, typename U, typename V>
197- constexpr auto operator +(S s, format_result<T, U, V> r) {
198- return format_result{s + r.str ,
199- transform (
200- [l = s.size ()](format_span sp) {
201- return format_span{sp.begin_idx + l,
202- sp.end_idx + l};
203- },
204- r.spans ),
205- r.args };
237+ template <typename S, typename Str, typename Args, typename Spans>
238+ constexpr auto operator +(S s, format_result<Str, Args, Spans> r) {
239+ return make_format_result<detail::apply_offset<s.size (), Spans>>(s + r.str ,
240+ r.args );
206241}
207242
208- template <typename A, typename B, typename C, typename T, typename U,
209- typename V>
210- constexpr auto operator +(format_result<A, B, C> r1, format_result<T, U, V> r2) {
211- return format_result{
212- r1.str + r2.str ,
213- tuple_cat (r1.spans , transform (
214- [l = r1.str .size ()](format_span sp) {
215- return format_span{sp.begin_idx + l,
216- sp.end_idx + l};
217- },
218- r2.spans )),
219- tuple_cat (r1.args , r2.args )};
243+ template <typename Str1, typename Args1, typename Spans1, typename Str2,
244+ typename Args2, typename Spans2>
245+ constexpr auto operator +(format_result<Str1, Args1, Spans1> r1,
246+ format_result<Str2, Args2, Spans2> r2) {
247+ return make_format_result<boost::mp11::mp_append<
248+ Spans1, detail::apply_offset<r1.str .size (), Spans2>>>(
249+ r1.str + r2.str , tuple_cat (r1.args , r2.args ));
220250}
221251
222252template <typename T, T...> struct null_output ;
@@ -260,34 +290,25 @@ constexpr auto format1(Arg arg) {
260290 constexpr auto s = convert_input (a.str );
261291 constexpr auto sz = fmt::formatted_size (fmtstr, s);
262292 constexpr auto cts = perform_format<sz>(fmtstr, s);
263- return format_result{cts_t <cts>{},
264- transform (
265- [](format_span sp) {
266- return format_span{sp.begin_idx +
267- Start,
268- sp.end_idx + Start};
269- },
270- a.spans ),
271- a.args };
293+ using Spans = typename std::remove_cvref_t <decltype (a)>::spans_t ;
294+ return make_format_result<detail::apply_offset<Start, Spans>>(
295+ cts_t <cts>{}, a.args );
272296 } else {
297+ using arg_t = stdx::remove_cvref_t <decltype (arg_type (arg))>;
273298 constexpr auto sz = fmt::formatted_size (fmtstr, a);
274299 constexpr auto cts = perform_format<sz>(fmtstr, a);
275- constexpr auto span = format_span{Start, sz};
276- return format_result{cts_t <cts>{}, tuple{span}};
300+ using Spans = type_list<format_span<Start, sz>>;
301+ return make_format_result<Spans>(cts_t <cts>{},
302+ tuple{ct_format_arg<arg_t >{}});
277303 }
278304 } else if constexpr (is_specialization_of_v<Arg, format_result>) {
279305 auto const sub_result = format1<Fmt, Start>(arg.str );
280- return format_result{sub_result.str ,
281- transform (
282- [](format_span sp) {
283- return format_span{sp.begin_idx + Start,
284- sp.end_idx + Start};
285- },
286- arg.spans ),
287- arg.args };
306+ using Spans = typename Arg::spans_t ;
307+ return make_format_result<detail::apply_offset<Start, Spans>>(
308+ sub_result.str , arg.args );
288309 } else {
289- constexpr auto span = format_span{ Start, Fmt.size ()} ;
290- return format_result{ cts_t <Fmt>{}, tuple{span}, tuple{ arg}} ;
310+ using Spans = type_list< format_span< Start, Fmt.size ()>> ;
311+ return make_format_result<Spans>( cts_t <Fmt>{}, tuple{arg}) ;
291312 }
292313}
293314
@@ -334,10 +355,11 @@ constexpr auto ct_format = [](auto &&...args) {
334355 auto const result = [&]<std::size_t ... Is>(std::index_sequence<Is...>) {
335356 using detail::ct_format_as;
336357 return (format1.template operator ()<Is>(ct_format_as (FWD (args))) + ... +
337- format_result{ cts_t <data::last_cts>{}} );
358+ make_format_result ( cts_t <data::last_cts>{}) );
338359 }(std::make_index_sequence<data::N>{});
339360 constexpr auto str = detail::convert_output<result.str .value , Output>();
340- return format_result{str, result.spans , result.args };
361+ using Spans = typename std::remove_cvref_t <decltype (result)>::spans_t ;
362+ return make_format_result<Spans>(str, result.args );
341363};
342364
343365template <ct_string Fmt>
0 commit comments