You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

compile.h 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. // Formatting library for C++ - experimental format string compilation
  2. //
  3. // Copyright (c) 2012 - present, Victor Zverovich and fmt contributors
  4. // All rights reserved.
  5. //
  6. // For the license information refer to format.h.
  7. #ifndef FMT_COMPILE_H_
  8. #define FMT_COMPILE_H_
  9. #include <vector>
  10. #include "format.h"
  11. FMT_BEGIN_NAMESPACE
  12. namespace detail {
  13. // A compile-time string which is compiled into fast formatting code.
  14. class compiled_string {};
  15. template <typename S>
  16. struct is_compiled_string : std::is_base_of<compiled_string, S> {};
  17. /**
  18. \rst
  19. Converts a string literal *s* into a format string that will be parsed at
  20. compile time and converted into efficient formatting code. Requires C++17
  21. ``constexpr if`` compiler support.
  22. **Example**::
  23. // Converts 42 into std::string using the most efficient method and no
  24. // runtime format string processing.
  25. std::string s = fmt::format(FMT_COMPILE("{}"), 42);
  26. \endrst
  27. */
  28. #define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::detail::compiled_string)
  29. template <typename T, typename... Tail>
  30. const T& first(const T& value, const Tail&...) {
  31. return value;
  32. }
  33. // Part of a compiled format string. It can be either literal text or a
  34. // replacement field.
  35. template <typename Char> struct format_part {
  36. enum class kind { arg_index, arg_name, text, replacement };
  37. struct replacement {
  38. arg_ref<Char> arg_id;
  39. dynamic_format_specs<Char> specs;
  40. };
  41. kind part_kind;
  42. union value {
  43. int arg_index;
  44. basic_string_view<Char> str;
  45. replacement repl;
  46. FMT_CONSTEXPR value(int index = 0) : arg_index(index) {}
  47. FMT_CONSTEXPR value(basic_string_view<Char> s) : str(s) {}
  48. FMT_CONSTEXPR value(replacement r) : repl(r) {}
  49. } val;
  50. // Position past the end of the argument id.
  51. const Char* arg_id_end = nullptr;
  52. FMT_CONSTEXPR format_part(kind k = kind::arg_index, value v = {})
  53. : part_kind(k), val(v) {}
  54. static FMT_CONSTEXPR format_part make_arg_index(int index) {
  55. return format_part(kind::arg_index, index);
  56. }
  57. static FMT_CONSTEXPR format_part make_arg_name(basic_string_view<Char> name) {
  58. return format_part(kind::arg_name, name);
  59. }
  60. static FMT_CONSTEXPR format_part make_text(basic_string_view<Char> text) {
  61. return format_part(kind::text, text);
  62. }
  63. static FMT_CONSTEXPR format_part make_replacement(replacement repl) {
  64. return format_part(kind::replacement, repl);
  65. }
  66. };
  67. template <typename Char> struct part_counter {
  68. unsigned num_parts = 0;
  69. FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
  70. if (begin != end) ++num_parts;
  71. }
  72. FMT_CONSTEXPR int on_arg_id() { return ++num_parts, 0; }
  73. FMT_CONSTEXPR int on_arg_id(int) { return ++num_parts, 0; }
  74. FMT_CONSTEXPR int on_arg_id(basic_string_view<Char>) {
  75. return ++num_parts, 0;
  76. }
  77. FMT_CONSTEXPR void on_replacement_field(int, const Char*) {}
  78. FMT_CONSTEXPR const Char* on_format_specs(int, const Char* begin,
  79. const Char* end) {
  80. // Find the matching brace.
  81. unsigned brace_counter = 0;
  82. for (; begin != end; ++begin) {
  83. if (*begin == '{') {
  84. ++brace_counter;
  85. } else if (*begin == '}') {
  86. if (brace_counter == 0u) break;
  87. --brace_counter;
  88. }
  89. }
  90. return begin;
  91. }
  92. FMT_CONSTEXPR void on_error(const char*) {}
  93. };
  94. // Counts the number of parts in a format string.
  95. template <typename Char>
  96. FMT_CONSTEXPR unsigned count_parts(basic_string_view<Char> format_str) {
  97. part_counter<Char> counter;
  98. parse_format_string<true>(format_str, counter);
  99. return counter.num_parts;
  100. }
  101. template <typename Char, typename PartHandler>
  102. class format_string_compiler : public error_handler {
  103. private:
  104. using part = format_part<Char>;
  105. PartHandler handler_;
  106. part part_;
  107. basic_string_view<Char> format_str_;
  108. basic_format_parse_context<Char> parse_context_;
  109. public:
  110. FMT_CONSTEXPR format_string_compiler(basic_string_view<Char> format_str,
  111. PartHandler handler)
  112. : handler_(handler),
  113. format_str_(format_str),
  114. parse_context_(format_str) {}
  115. FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
  116. if (begin != end)
  117. handler_(part::make_text({begin, to_unsigned(end - begin)}));
  118. }
  119. FMT_CONSTEXPR int on_arg_id() {
  120. part_ = part::make_arg_index(parse_context_.next_arg_id());
  121. return 0;
  122. }
  123. FMT_CONSTEXPR int on_arg_id(int id) {
  124. parse_context_.check_arg_id(id);
  125. part_ = part::make_arg_index(id);
  126. return 0;
  127. }
  128. FMT_CONSTEXPR int on_arg_id(basic_string_view<Char> id) {
  129. part_ = part::make_arg_name(id);
  130. return 0;
  131. }
  132. FMT_CONSTEXPR void on_replacement_field(int, const Char* ptr) {
  133. part_.arg_id_end = ptr;
  134. handler_(part_);
  135. }
  136. FMT_CONSTEXPR const Char* on_format_specs(int, const Char* begin,
  137. const Char* end) {
  138. auto repl = typename part::replacement();
  139. dynamic_specs_handler<basic_format_parse_context<Char>> handler(
  140. repl.specs, parse_context_);
  141. auto it = parse_format_specs(begin, end, handler);
  142. if (*it != '}') on_error("missing '}' in format string");
  143. repl.arg_id = part_.part_kind == part::kind::arg_index
  144. ? arg_ref<Char>(part_.val.arg_index)
  145. : arg_ref<Char>(part_.val.str);
  146. auto part = part::make_replacement(repl);
  147. part.arg_id_end = begin;
  148. handler_(part);
  149. return it;
  150. }
  151. };
  152. // Compiles a format string and invokes handler(part) for each parsed part.
  153. template <bool IS_CONSTEXPR, typename Char, typename PartHandler>
  154. FMT_CONSTEXPR void compile_format_string(basic_string_view<Char> format_str,
  155. PartHandler handler) {
  156. parse_format_string<IS_CONSTEXPR>(
  157. format_str,
  158. format_string_compiler<Char, PartHandler>(format_str, handler));
  159. }
  160. template <typename OutputIt, typename Context, typename Id>
  161. void format_arg(
  162. basic_format_parse_context<typename Context::char_type>& parse_ctx,
  163. Context& ctx, Id arg_id) {
  164. ctx.advance_to(visit_format_arg(
  165. arg_formatter<OutputIt, typename Context::char_type>(ctx, &parse_ctx),
  166. ctx.arg(arg_id)));
  167. }
  168. // vformat_to is defined in a subnamespace to prevent ADL.
  169. namespace cf {
  170. template <typename Context, typename OutputIt, typename CompiledFormat>
  171. auto vformat_to(OutputIt out, CompiledFormat& cf,
  172. basic_format_args<Context> args) -> typename Context::iterator {
  173. using char_type = typename Context::char_type;
  174. basic_format_parse_context<char_type> parse_ctx(
  175. to_string_view(cf.format_str_));
  176. Context ctx(out, args);
  177. const auto& parts = cf.parts();
  178. for (auto part_it = std::begin(parts); part_it != std::end(parts);
  179. ++part_it) {
  180. const auto& part = *part_it;
  181. const auto& value = part.val;
  182. using format_part_t = format_part<char_type>;
  183. switch (part.part_kind) {
  184. case format_part_t::kind::text: {
  185. const auto text = value.str;
  186. auto output = ctx.out();
  187. auto&& it = reserve(output, text.size());
  188. it = std::copy_n(text.begin(), text.size(), it);
  189. ctx.advance_to(output);
  190. break;
  191. }
  192. case format_part_t::kind::arg_index:
  193. advance_to(parse_ctx, part.arg_id_end);
  194. detail::format_arg<OutputIt>(parse_ctx, ctx, value.arg_index);
  195. break;
  196. case format_part_t::kind::arg_name:
  197. advance_to(parse_ctx, part.arg_id_end);
  198. detail::format_arg<OutputIt>(parse_ctx, ctx, value.str);
  199. break;
  200. case format_part_t::kind::replacement: {
  201. const auto& arg_id_value = value.repl.arg_id.val;
  202. const auto arg = value.repl.arg_id.kind == arg_id_kind::index
  203. ? ctx.arg(arg_id_value.index)
  204. : ctx.arg(arg_id_value.name);
  205. auto specs = value.repl.specs;
  206. handle_dynamic_spec<width_checker>(specs.width, specs.width_ref, ctx);
  207. handle_dynamic_spec<precision_checker>(specs.precision,
  208. specs.precision_ref, ctx);
  209. error_handler h;
  210. numeric_specs_checker<error_handler> checker(h, arg.type());
  211. if (specs.align == align::numeric) checker.require_numeric_argument();
  212. if (specs.sign != sign::none) checker.check_sign();
  213. if (specs.alt) checker.require_numeric_argument();
  214. if (specs.precision >= 0) checker.check_precision();
  215. advance_to(parse_ctx, part.arg_id_end);
  216. ctx.advance_to(
  217. visit_format_arg(arg_formatter<OutputIt, typename Context::char_type>(
  218. ctx, nullptr, &specs),
  219. arg));
  220. break;
  221. }
  222. }
  223. }
  224. return ctx.out();
  225. }
  226. } // namespace cf
  227. struct basic_compiled_format {};
  228. template <typename S, typename = void>
  229. struct compiled_format_base : basic_compiled_format {
  230. using char_type = char_t<S>;
  231. using parts_container = std::vector<detail::format_part<char_type>>;
  232. parts_container compiled_parts;
  233. explicit compiled_format_base(basic_string_view<char_type> format_str) {
  234. compile_format_string<false>(format_str,
  235. [this](const format_part<char_type>& part) {
  236. compiled_parts.push_back(part);
  237. });
  238. }
  239. const parts_container& parts() const { return compiled_parts; }
  240. };
  241. template <typename Char, unsigned N> struct format_part_array {
  242. format_part<Char> data[N] = {};
  243. FMT_CONSTEXPR format_part_array() = default;
  244. };
  245. template <typename Char, unsigned N>
  246. FMT_CONSTEXPR format_part_array<Char, N> compile_to_parts(
  247. basic_string_view<Char> format_str) {
  248. format_part_array<Char, N> parts;
  249. unsigned counter = 0;
  250. // This is not a lambda for compatibility with older compilers.
  251. struct {
  252. format_part<Char>* parts;
  253. unsigned* counter;
  254. FMT_CONSTEXPR void operator()(const format_part<Char>& part) {
  255. parts[(*counter)++] = part;
  256. }
  257. } collector{parts.data, &counter};
  258. compile_format_string<true>(format_str, collector);
  259. if (counter < N) {
  260. parts.data[counter] =
  261. format_part<Char>::make_text(basic_string_view<Char>());
  262. }
  263. return parts;
  264. }
  265. template <typename T> constexpr const T& constexpr_max(const T& a, const T& b) {
  266. return (a < b) ? b : a;
  267. }
  268. template <typename S>
  269. struct compiled_format_base<S, enable_if_t<is_compile_string<S>::value>>
  270. : basic_compiled_format {
  271. using char_type = char_t<S>;
  272. FMT_CONSTEXPR explicit compiled_format_base(basic_string_view<char_type>) {}
  273. // Workaround for old compilers. Format string compilation will not be
  274. // performed there anyway.
  275. #if FMT_USE_CONSTEXPR
  276. static FMT_CONSTEXPR_DECL const unsigned num_format_parts =
  277. constexpr_max(count_parts(to_string_view(S())), 1u);
  278. #else
  279. static const unsigned num_format_parts = 1;
  280. #endif
  281. using parts_container = format_part<char_type>[num_format_parts];
  282. const parts_container& parts() const {
  283. static FMT_CONSTEXPR_DECL const auto compiled_parts =
  284. compile_to_parts<char_type, num_format_parts>(
  285. detail::to_string_view(S()));
  286. return compiled_parts.data;
  287. }
  288. };
  289. template <typename S, typename... Args>
  290. class compiled_format : private compiled_format_base<S> {
  291. public:
  292. using typename compiled_format_base<S>::char_type;
  293. private:
  294. basic_string_view<char_type> format_str_;
  295. template <typename Context, typename OutputIt, typename CompiledFormat>
  296. friend auto cf::vformat_to(OutputIt out, CompiledFormat& cf,
  297. basic_format_args<Context> args) ->
  298. typename Context::iterator;
  299. public:
  300. compiled_format() = delete;
  301. explicit constexpr compiled_format(basic_string_view<char_type> format_str)
  302. : compiled_format_base<S>(format_str), format_str_(format_str) {}
  303. };
  304. #ifdef __cpp_if_constexpr
  305. template <typename... Args> struct type_list {};
  306. // Returns a reference to the argument at index N from [first, rest...].
  307. template <int N, typename T, typename... Args>
  308. constexpr const auto& get([[maybe_unused]] const T& first,
  309. [[maybe_unused]] const Args&... rest) {
  310. static_assert(N < 1 + sizeof...(Args), "index is out of bounds");
  311. if constexpr (N == 0)
  312. return first;
  313. else
  314. return get<N - 1>(rest...);
  315. }
  316. template <int N, typename> struct get_type_impl;
  317. template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> {
  318. using type = remove_cvref_t<decltype(get<N>(std::declval<Args>()...))>;
  319. };
  320. template <int N, typename T>
  321. using get_type = typename get_type_impl<N, T>::type;
  322. template <typename T> struct is_compiled_format : std::false_type {};
  323. template <typename Char> struct text {
  324. basic_string_view<Char> data;
  325. using char_type = Char;
  326. template <typename OutputIt, typename... Args>
  327. OutputIt format(OutputIt out, const Args&...) const {
  328. return write<Char>(out, data);
  329. }
  330. };
  331. template <typename Char>
  332. struct is_compiled_format<text<Char>> : std::true_type {};
  333. template <typename Char>
  334. constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos,
  335. size_t size) {
  336. return {{&s[pos], size}};
  337. }
  338. template <typename Char> struct code_unit {
  339. Char value;
  340. using char_type = Char;
  341. template <typename OutputIt, typename... Args>
  342. OutputIt format(OutputIt out, const Args&...) const {
  343. return write<Char>(out, value);
  344. }
  345. };
  346. template <typename Char>
  347. struct is_compiled_format<code_unit<Char>> : std::true_type {};
  348. // A replacement field that refers to argument N.
  349. template <typename Char, typename T, int N> struct field {
  350. using char_type = Char;
  351. template <typename OutputIt, typename... Args>
  352. OutputIt format(OutputIt out, const Args&... args) const {
  353. // This ensures that the argument type is convertile to `const T&`.
  354. const T& arg = get<N>(args...);
  355. return write<Char>(out, arg);
  356. }
  357. };
  358. template <typename Char, typename T, int N>
  359. struct is_compiled_format<field<Char, T, N>> : std::true_type {};
  360. // A replacement field that refers to argument N and has format specifiers.
  361. template <typename Char, typename T, int N> struct spec_field {
  362. using char_type = Char;
  363. mutable formatter<T, Char> fmt;
  364. template <typename OutputIt, typename... Args>
  365. OutputIt format(OutputIt out, const Args&... args) const {
  366. // This ensures that the argument type is convertile to `const T&`.
  367. const T& arg = get<N>(args...);
  368. const auto& vargs =
  369. make_format_args<basic_format_context<OutputIt, Char>>(args...);
  370. basic_format_context<OutputIt, Char> ctx(out, vargs);
  371. return fmt.format(arg, ctx);
  372. }
  373. };
  374. template <typename Char, typename T, int N>
  375. struct is_compiled_format<spec_field<Char, T, N>> : std::true_type {};
  376. template <typename L, typename R> struct concat {
  377. L lhs;
  378. R rhs;
  379. using char_type = typename L::char_type;
  380. template <typename OutputIt, typename... Args>
  381. OutputIt format(OutputIt out, const Args&... args) const {
  382. out = lhs.format(out, args...);
  383. return rhs.format(out, args...);
  384. }
  385. };
  386. template <typename L, typename R>
  387. struct is_compiled_format<concat<L, R>> : std::true_type {};
  388. template <typename L, typename R>
  389. constexpr concat<L, R> make_concat(L lhs, R rhs) {
  390. return {lhs, rhs};
  391. }
  392. struct unknown_format {};
  393. template <typename Char>
  394. constexpr size_t parse_text(basic_string_view<Char> str, size_t pos) {
  395. for (size_t size = str.size(); pos != size; ++pos) {
  396. if (str[pos] == '{' || str[pos] == '}') break;
  397. }
  398. return pos;
  399. }
  400. template <typename Args, size_t POS, int ID, typename S>
  401. constexpr auto compile_format_string(S format_str);
  402. template <typename Args, size_t POS, int ID, typename T, typename S>
  403. constexpr auto parse_tail(T head, S format_str) {
  404. if constexpr (POS !=
  405. basic_string_view<typename S::char_type>(format_str).size()) {
  406. constexpr auto tail = compile_format_string<Args, POS, ID>(format_str);
  407. if constexpr (std::is_same<remove_cvref_t<decltype(tail)>,
  408. unknown_format>())
  409. return tail;
  410. else
  411. return make_concat(head, tail);
  412. } else {
  413. return head;
  414. }
  415. }
  416. template <typename T, typename Char> struct parse_specs_result {
  417. formatter<T, Char> fmt;
  418. size_t end;
  419. int next_arg_id;
  420. };
  421. template <typename T, typename Char>
  422. constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
  423. size_t pos, int arg_id) {
  424. str.remove_prefix(pos);
  425. auto ctx = basic_format_parse_context<Char>(str, {}, arg_id + 1);
  426. auto f = formatter<T, Char>();
  427. auto end = f.parse(ctx);
  428. return {f, pos + (end - str.data()) + 1, ctx.next_arg_id()};
  429. }
  430. // Compiles a non-empty format string and returns the compiled representation
  431. // or unknown_format() on unrecognized input.
  432. template <typename Args, size_t POS, int ID, typename S>
  433. constexpr auto compile_format_string(S format_str) {
  434. using char_type = typename S::char_type;
  435. constexpr basic_string_view<char_type> str = format_str;
  436. if constexpr (str[POS] == '{') {
  437. if (POS + 1 == str.size())
  438. throw format_error("unmatched '{' in format string");
  439. if constexpr (str[POS + 1] == '{') {
  440. return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
  441. } else if constexpr (str[POS + 1] == '}') {
  442. using type = get_type<ID, Args>;
  443. return parse_tail<Args, POS + 2, ID + 1>(field<char_type, type, ID>(),
  444. format_str);
  445. } else if constexpr (str[POS + 1] == ':') {
  446. using type = get_type<ID, Args>;
  447. constexpr auto result = parse_specs<type>(str, POS + 2, ID);
  448. return parse_tail<Args, result.end, result.next_arg_id>(
  449. spec_field<char_type, type, ID>{result.fmt}, format_str);
  450. } else {
  451. return unknown_format();
  452. }
  453. } else if constexpr (str[POS] == '}') {
  454. if (POS + 1 == str.size())
  455. throw format_error("unmatched '}' in format string");
  456. return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
  457. } else {
  458. constexpr auto end = parse_text(str, POS + 1);
  459. if constexpr (end - POS > 1) {
  460. return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
  461. format_str);
  462. } else {
  463. return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]},
  464. format_str);
  465. }
  466. }
  467. }
  468. template <typename... Args, typename S,
  469. FMT_ENABLE_IF(is_compile_string<S>::value ||
  470. detail::is_compiled_string<S>::value)>
  471. constexpr auto compile(S format_str) {
  472. constexpr basic_string_view<typename S::char_type> str = format_str;
  473. if constexpr (str.size() == 0) {
  474. return detail::make_text(str, 0, 0);
  475. } else {
  476. constexpr auto result =
  477. detail::compile_format_string<detail::type_list<Args...>, 0, 0>(
  478. format_str);
  479. if constexpr (std::is_same<remove_cvref_t<decltype(result)>,
  480. detail::unknown_format>()) {
  481. return detail::compiled_format<S, Args...>(to_string_view(format_str));
  482. } else {
  483. return result;
  484. }
  485. }
  486. }
  487. #else
  488. template <typename... Args, typename S,
  489. FMT_ENABLE_IF(is_compile_string<S>::value)>
  490. constexpr auto compile(S format_str) -> detail::compiled_format<S, Args...> {
  491. return detail::compiled_format<S, Args...>(to_string_view(format_str));
  492. }
  493. #endif // __cpp_if_constexpr
  494. // Compiles the format string which must be a string literal.
  495. template <typename... Args, typename Char, size_t N>
  496. auto compile(const Char (&format_str)[N])
  497. -> detail::compiled_format<const Char*, Args...> {
  498. return detail::compiled_format<const Char*, Args...>(
  499. basic_string_view<Char>(format_str, N - 1));
  500. }
  501. } // namespace detail
  502. // DEPRECATED! use FMT_COMPILE instead.
  503. template <typename... Args>
  504. FMT_DEPRECATED auto compile(const Args&... args)
  505. -> decltype(detail::compile(args...)) {
  506. return detail::compile(args...);
  507. }
  508. #if FMT_USE_CONSTEXPR
  509. # ifdef __cpp_if_constexpr
  510. template <typename CompiledFormat, typename... Args,
  511. typename Char = typename CompiledFormat::char_type,
  512. FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
  513. FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf,
  514. const Args&... args) {
  515. basic_memory_buffer<Char> buffer;
  516. cf.format(detail::buffer_appender<Char>(buffer), args...);
  517. return to_string(buffer);
  518. }
  519. template <typename OutputIt, typename CompiledFormat, typename... Args,
  520. FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
  521. OutputIt format_to(OutputIt out, const CompiledFormat& cf,
  522. const Args&... args) {
  523. return cf.format(out, args...);
  524. }
  525. # endif // __cpp_if_constexpr
  526. #endif // FMT_USE_CONSTEXPR
  527. template <typename CompiledFormat, typename... Args,
  528. typename Char = typename CompiledFormat::char_type,
  529. FMT_ENABLE_IF(std::is_base_of<detail::basic_compiled_format,
  530. CompiledFormat>::value)>
  531. std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
  532. basic_memory_buffer<Char> buffer;
  533. using context = buffer_context<Char>;
  534. detail::cf::vformat_to<context>(detail::buffer_appender<Char>(buffer), cf,
  535. make_format_args<context>(args...));
  536. return to_string(buffer);
  537. }
  538. template <typename S, typename... Args,
  539. FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
  540. FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
  541. Args&&... args) {
  542. #ifdef __cpp_if_constexpr
  543. if constexpr (std::is_same<typename S::char_type, char>::value) {
  544. constexpr basic_string_view<typename S::char_type> str = S();
  545. if (str.size() == 2 && str[0] == '{' && str[1] == '}')
  546. return fmt::to_string(detail::first(args...));
  547. }
  548. #endif
  549. constexpr auto compiled = detail::compile<Args...>(S());
  550. return format(compiled, std::forward<Args>(args)...);
  551. }
  552. template <typename OutputIt, typename CompiledFormat, typename... Args,
  553. FMT_ENABLE_IF(std::is_base_of<detail::basic_compiled_format,
  554. CompiledFormat>::value)>
  555. OutputIt format_to(OutputIt out, const CompiledFormat& cf,
  556. const Args&... args) {
  557. using char_type = typename CompiledFormat::char_type;
  558. using context = format_context_t<OutputIt, char_type>;
  559. return detail::cf::vformat_to<context>(out, cf,
  560. make_format_args<context>(args...));
  561. }
  562. template <typename OutputIt, typename S, typename... Args,
  563. FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
  564. OutputIt format_to(OutputIt out, const S&, const Args&... args) {
  565. constexpr auto compiled = detail::compile<Args...>(S());
  566. return format_to(out, compiled, args...);
  567. }
  568. template <typename OutputIt, typename CompiledFormat, typename... Args>
  569. auto format_to_n(OutputIt out, size_t n, const CompiledFormat& cf,
  570. const Args&... args) ->
  571. typename std::enable_if<
  572. detail::is_output_iterator<OutputIt,
  573. typename CompiledFormat::char_type>::value &&
  574. std::is_base_of<detail::basic_compiled_format,
  575. CompiledFormat>::value,
  576. format_to_n_result<OutputIt>>::type {
  577. auto it =
  578. format_to(detail::truncating_iterator<OutputIt>(out, n), cf, args...);
  579. return {it.base(), it.count()};
  580. }
  581. template <typename OutputIt, typename S, typename... Args,
  582. FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
  583. format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n, const S&,
  584. const Args&... args) {
  585. constexpr auto compiled = detail::compile<Args...>(S());
  586. auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), compiled,
  587. args...);
  588. return {it.base(), it.count()};
  589. }
  590. template <typename CompiledFormat, typename... Args>
  591. size_t formatted_size(const CompiledFormat& cf, const Args&... args) {
  592. return format_to(detail::counting_iterator(), cf, args...).count();
  593. }
  594. FMT_END_NAMESPACE
  595. #endif // FMT_COMPILE_H_