#pragma once #if __cplusplus >= 202002L #include #include #include #include #include #include #include #include #include #include #include #include #include #include template struct fmt::formatter> : fmt::formatter { template constexpr auto format(stdx::ct_string const &s, Ctx &ctx) const { return fmt::formatter::format(std::string_view{s}, ctx); } }; namespace stdx { inline namespace v1 { template struct format_result { [[no_unique_address]] Str str; [[no_unique_address]] Args args{}; private: friend constexpr auto operator==(format_result const &, format_result const &) -> bool = default; }; template format_result(Str, Args) -> format_result; template format_result(Str) -> format_result>; inline namespace literals { inline namespace ct_string_literals { template CONSTEVAL auto operator""_fmt_res() { return format_result{cts_t{}}; } } // namespace ct_string_literals } // namespace literals namespace detail { template CONSTEVAL auto find_spec(It first, It last) -> It { for (auto spec_start = std::find(first, last, '{'); spec_start != last; spec_start = std::find(spec_start, last, '{')) { if (spec_start + 1 != last) { if (*std::next(spec_start) != '{') { return spec_start; } ++spec_start; } ++spec_start; } return last; } CONSTEVAL auto count_specifiers(std::string_view fmt) -> std::size_t { auto count = std::size_t{}; for (auto spec_start = find_spec(fmt.begin(), fmt.end()); spec_start != fmt.end(); spec_start = find_spec(++spec_start, fmt.end())) { ++count; } return count; } template CONSTEVAL auto split_specifiers(std::string_view fmt) { auto splits = std::array{}; auto count = std::size_t{}; auto split_start = fmt.begin(); auto spec_start = find_spec(fmt.begin(), fmt.end()); while (spec_start != fmt.end()) { auto split_end = std::find(spec_start, fmt.end(), '}'); if (split_end != fmt.end()) { ++split_end; } splits[count++] = std::string_view{split_start, split_end}; split_start = split_end; spec_start = find_spec(split_start, fmt.end()); } splits[count++] = std::string_view{split_start, spec_start}; return splits; } template concept cx_value = requires { typename T::cx_value_t; } or requires(T t) { ct_string_from_type(t); }; template CONSTEVAL auto arg_value(std::integral_constant) { if constexpr (std::is_enum_v) { return enum_as_string(); } else { return V; } } template CONSTEVAL auto arg_value(type_identity) { return type_as_string(); } template CONSTEVAL auto arg_value(cts_t) { return S; } CONSTEVAL auto arg_value(cx_value auto a) { if constexpr (requires { ct_string_from_type(a); }) { return ct_string_from_type(a); } else if constexpr (std::is_enum_v) { return enum_as_string(); } else if constexpr (requires { arg_value(a()); }) { return arg_value(a()); } else { return a(); } } template constexpr auto operator+(format_result r, S s) { return format_result{r.str + s, r.args}; } template constexpr auto operator+(S s, format_result r) { return format_result{s + r.str, r.args}; } template constexpr auto operator+(format_result r1, format_result r2) { return format_result{r1.str + r2.str, tuple_cat(r1.args, r2.args)}; } template struct null_output; template CONSTEVAL auto to_ct_string(std::string_view s) { return ct_string{s.data(), s.size()}; } CONSTEVAL auto convert_input(auto s) { if constexpr (requires { ct_string_from_type(s); }) { return ct_string_from_type(s); } else { return s.value; } } template typename Output = detail::null_output> CONSTEVAL auto convert_output() { if constexpr (same_as, null_output>) { return cts_t{}; } else { return ct_string_to_type(); } } template constexpr auto format1(Arg arg) { if constexpr (requires { arg_value(arg); }) { constexpr auto fmtstr = FMT_COMPILE(std::string_view{Fmt}); constexpr auto a = arg_value(arg); auto const f = [](auto s, auto v) { ct_string cts{}; fmt::format_to(cts.begin(), s, v); return cts; }; if constexpr (is_specialization_of_v, format_result>) { constexpr auto s = convert_input(a.str); constexpr auto sz = fmt::formatted_size(fmtstr, s); constexpr auto cts = f.template operator()(fmtstr, s); return format_result{cts_t{}, a.args}; } else { constexpr auto sz = fmt::formatted_size(fmtstr, a); constexpr auto cts = f.template operator()(fmtstr, a); return format_result{cts_t{}}; } } else if constexpr (is_specialization_of_v) { auto const sub_result = format1(arg.str); return format_result{sub_result.str, arg.args}; } else { return format_result{cts_t{}, tuple{arg}}; } } template