Skip to content

Commit 4fec5f8

Browse files
committed
wip
1 parent 9496fa4 commit 4fec5f8

2 files changed

Lines changed: 450 additions & 326 deletions

File tree

include/stdx/ct_format.hpp

Lines changed: 89 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
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

92118
inline namespace literals {
93119
inline namespace ct_string_literals {
94120
template <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>) {
177203
template <ct_string S> CONSTEVAL auto arg_value(cts_t<S>) { return S; }
178204

179205
CONSTEVAL 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

222252
template <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

343365
template <ct_string Fmt>

0 commit comments

Comments
 (0)