]>
Commit | Line | Data |
---|---|---|
9f95a23c TL |
1 | // Formatting library for C++ - 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 | ||
8 | #ifndef FMT_PREPARE_H_ | |
9 | #define FMT_PREPARE_H_ | |
10 | ||
11 | #ifndef FMT_HAS_CONSTRUCTIBLE_TRAITS | |
12 | # define FMT_HAS_CONSTRUCTIBLE_TRAITS \ | |
13 | (FMT_GCC_VERSION >= 407 || FMT_CLANG_VERSION || FMT_MSC_VER) | |
14 | #endif | |
15 | ||
16 | #include "format.h" | |
17 | ||
18 | #include <vector> | |
19 | ||
20 | FMT_BEGIN_NAMESPACE | |
21 | ||
22 | template <typename Char> struct format_part { | |
23 | public: | |
24 | struct named_argument_id { | |
25 | FMT_CONSTEXPR named_argument_id(internal::string_view_metadata id) | |
26 | : id(id) {} | |
27 | internal::string_view_metadata id; | |
28 | }; | |
29 | ||
30 | struct argument_id { | |
31 | FMT_CONSTEXPR argument_id() : argument_id(0u) {} | |
32 | ||
33 | FMT_CONSTEXPR argument_id(unsigned id) | |
34 | : which(which_arg_id::index), val(id) {} | |
35 | ||
36 | FMT_CONSTEXPR argument_id(internal::string_view_metadata id) | |
37 | : which(which_arg_id::named_index), val(id) {} | |
38 | ||
39 | enum class which_arg_id { index, named_index }; | |
40 | ||
41 | which_arg_id which; | |
42 | ||
43 | FMT_UNRESTRICTED_UNION value { | |
44 | FMT_CONSTEXPR value() : index(0u) {} | |
45 | FMT_CONSTEXPR value(unsigned id) : index(id) {} | |
46 | FMT_CONSTEXPR value(internal::string_view_metadata id) | |
47 | : named_index(id) {} | |
48 | ||
49 | unsigned index; | |
50 | internal::string_view_metadata named_index; | |
51 | } | |
52 | val; | |
53 | }; | |
54 | ||
55 | struct specification { | |
56 | FMT_CONSTEXPR specification() : arg_id(0u) {} | |
57 | FMT_CONSTEXPR specification(unsigned id) : arg_id(id) {} | |
58 | ||
59 | FMT_CONSTEXPR specification(internal::string_view_metadata id) | |
60 | : arg_id(id) {} | |
61 | ||
62 | argument_id arg_id; | |
63 | internal::dynamic_format_specs<Char> parsed_specs; | |
64 | }; | |
65 | ||
66 | FMT_CONSTEXPR format_part() | |
67 | : which(which_value::argument_id), end_of_argument_id(0u), val(0u) {} | |
68 | ||
69 | FMT_CONSTEXPR format_part(internal::string_view_metadata text) | |
70 | : which(which_value::text), end_of_argument_id(0u), val(text) {} | |
71 | ||
72 | FMT_CONSTEXPR format_part(unsigned id) | |
73 | : which(which_value::argument_id), end_of_argument_id(0u), val(id) {} | |
74 | ||
75 | FMT_CONSTEXPR format_part(named_argument_id arg_id) | |
76 | : which(which_value::named_argument_id), | |
77 | end_of_argument_id(0u), | |
78 | val(arg_id) {} | |
79 | ||
80 | FMT_CONSTEXPR format_part(specification spec) | |
81 | : which(which_value::specification), end_of_argument_id(0u), val(spec) {} | |
82 | ||
83 | enum class which_value { | |
84 | argument_id, | |
85 | named_argument_id, | |
86 | text, | |
87 | specification | |
88 | }; | |
89 | ||
90 | which_value which; | |
91 | std::size_t end_of_argument_id; | |
92 | FMT_UNRESTRICTED_UNION value { | |
93 | FMT_CONSTEXPR value() : arg_id(0u) {} | |
94 | FMT_CONSTEXPR value(unsigned id) : arg_id(id) {} | |
95 | FMT_CONSTEXPR value(named_argument_id named_id) | |
96 | : named_arg_id(named_id.id) {} | |
97 | FMT_CONSTEXPR value(internal::string_view_metadata t) : text(t) {} | |
98 | FMT_CONSTEXPR value(specification s) : spec(s) {} | |
99 | unsigned arg_id; | |
100 | internal::string_view_metadata named_arg_id; | |
101 | internal::string_view_metadata text; | |
102 | specification spec; | |
103 | } | |
104 | val; | |
105 | }; | |
106 | ||
107 | namespace internal { | |
108 | template <typename Char, typename PartsContainer> | |
109 | class format_preparation_handler : public internal::error_handler { | |
110 | private: | |
111 | typedef format_part<Char> part; | |
112 | ||
113 | public: | |
114 | typedef internal::null_terminating_iterator<Char> iterator; | |
115 | ||
116 | FMT_CONSTEXPR format_preparation_handler(basic_string_view<Char> format, | |
117 | PartsContainer& parts) | |
118 | : parts_(parts), format_(format), parse_context_(format) {} | |
119 | ||
120 | FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { | |
121 | if (begin == end) { | |
122 | return; | |
123 | } | |
124 | const auto offset = begin - format_.data(); | |
125 | const auto size = end - begin; | |
126 | parts_.add(part(string_view_metadata(offset, size))); | |
127 | } | |
128 | ||
129 | FMT_CONSTEXPR void on_arg_id() { | |
130 | parts_.add(part(parse_context_.next_arg_id())); | |
131 | } | |
132 | ||
133 | FMT_CONSTEXPR void on_arg_id(unsigned id) { | |
134 | parse_context_.check_arg_id(id); | |
135 | parts_.add(part(id)); | |
136 | } | |
137 | ||
138 | FMT_CONSTEXPR void on_arg_id(basic_string_view<Char> id) { | |
139 | const auto view = string_view_metadata(format_, id); | |
140 | const auto arg_id = typename part::named_argument_id(view); | |
141 | parts_.add(part(arg_id)); | |
142 | } | |
143 | ||
144 | FMT_CONSTEXPR void on_replacement_field(const Char* ptr) { | |
145 | auto last_part = parts_.last(); | |
146 | last_part.end_of_argument_id = ptr - format_.begin(); | |
147 | parts_.substitute_last(last_part); | |
148 | } | |
149 | ||
150 | FMT_CONSTEXPR const Char* on_format_specs(const Char* begin, | |
151 | const Char* end) { | |
152 | const auto specs_offset = to_unsigned(begin - format_.begin()); | |
153 | ||
154 | typedef basic_parse_context<Char> parse_context; | |
155 | internal::dynamic_format_specs<Char> parsed_specs; | |
156 | dynamic_specs_handler<parse_context> handler(parsed_specs, parse_context_); | |
157 | begin = parse_format_specs(begin, end, handler); | |
158 | ||
159 | if (*begin != '}') { | |
160 | on_error("missing '}' in format string"); | |
161 | } | |
162 | ||
163 | const auto last_part = parts_.last(); | |
164 | ||
165 | auto specs = last_part.which == part::which_value::argument_id | |
166 | ? typename part::specification(last_part.val.arg_id) | |
167 | : typename part::specification(last_part.val.named_arg_id); | |
168 | ||
169 | specs.parsed_specs = parsed_specs; | |
170 | ||
171 | auto new_part = part(specs); | |
172 | new_part.end_of_argument_id = specs_offset; | |
173 | ||
174 | parts_.substitute_last(new_part); | |
175 | ||
176 | return begin; | |
177 | } | |
178 | ||
179 | private: | |
180 | PartsContainer& parts_; | |
181 | basic_string_view<Char> format_; | |
182 | basic_parse_context<Char> parse_context_; | |
183 | }; | |
184 | ||
185 | template <typename Format, typename PreparedPartsProvider, typename... Args> | |
186 | class prepared_format { | |
187 | public: | |
188 | typedef FMT_CHAR(Format) char_type; | |
189 | typedef format_part<char_type> format_part_t; | |
190 | ||
191 | prepared_format(Format f) | |
192 | : format_(std::move(f)), parts_provider_(to_string_view(format_)) {} | |
193 | ||
194 | prepared_format() = delete; | |
195 | ||
196 | std::size_t formatted_size(const Args&... args) const { | |
197 | const auto it = this->format_to(counting_iterator<char_type>(), args...); | |
198 | return it.count(); | |
199 | } | |
200 | ||
201 | template <typename OutputIt, | |
202 | FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value)> | |
203 | inline format_to_n_result<OutputIt> format_to_n(OutputIt out, unsigned n, | |
204 | const Args&... args) const { | |
205 | format_arg_store<typename format_to_n_context<OutputIt, char_type>::type, | |
206 | Args...> | |
207 | as(args...); | |
208 | ||
209 | typedef truncating_iterator<OutputIt> trunc_it; | |
210 | typedef output_range<trunc_it, char_type> range; | |
211 | range r(trunc_it(out, n)); | |
212 | auto it = this->vformat_to( | |
213 | r, typename format_to_n_args<OutputIt, char_type>::type(as)); | |
214 | return {it.base(), it.count()}; | |
215 | } | |
216 | ||
217 | std::basic_string<char_type> format(const Args&... args) const { | |
218 | basic_memory_buffer<char_type> buffer; | |
219 | typedef back_insert_range<internal::basic_buffer<char_type>> range; | |
220 | this->vformat_to(range(buffer), make_args_checked(format_, args...)); | |
221 | return to_string(buffer); | |
222 | } | |
223 | ||
224 | template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)> | |
225 | inline std::back_insert_iterator<Container> format_to( | |
226 | std::back_insert_iterator<Container> out, const Args&... args) const { | |
227 | internal::container_buffer<Container> buffer(internal::get_container(out)); | |
228 | typedef back_insert_range<internal::basic_buffer<char_type>> range; | |
229 | this->vformat_to(range(buffer), make_args_checked(format_, args...)); | |
230 | return out; | |
231 | } | |
232 | ||
233 | template <typename OutputIt> | |
234 | inline OutputIt format_to(OutputIt out, const Args&... args) const { | |
235 | typedef typename format_context_t<OutputIt, char_type>::type context; | |
236 | typedef output_range<OutputIt, char_type> range; | |
237 | format_arg_store<context, Args...> as(args...); | |
238 | return this->vformat_to(range(out), basic_format_args<context>(as)); | |
239 | } | |
240 | ||
241 | template <std::size_t SIZE = inline_buffer_size> | |
242 | inline typename buffer_context<char_type>::type::iterator format_to( | |
243 | basic_memory_buffer<char_type, SIZE>& buf, const Args&... args) const { | |
244 | typedef back_insert_range<internal::basic_buffer<char_type>> range; | |
245 | return this->vformat_to(range(buf), make_args_checked(format_, args...)); | |
246 | } | |
247 | ||
248 | private: | |
249 | typedef typename buffer_context<char_type>::type context; | |
250 | ||
251 | template <typename Range> | |
252 | typename context::iterator vformat_to(Range out, | |
253 | basic_format_args<context> args) const { | |
254 | const auto format_view = internal::to_string_view(format_); | |
255 | basic_parse_context<char_type> parse_ctx(format_view); | |
256 | context ctx(out.begin(), args); | |
257 | ||
258 | const auto& parts = parts_provider_.parts(); | |
259 | for (auto part_it = parts.begin(); part_it != parts.end(); ++part_it) { | |
260 | const auto& part = *part_it; | |
261 | const auto& value = part.val; | |
262 | ||
263 | switch (part.which) { | |
264 | case format_part_t::which_value::text: { | |
265 | const auto text = value.text.to_view(format_view); | |
266 | auto output = ctx.out(); | |
267 | auto&& it = internal::reserve(output, text.size()); | |
268 | it = std::copy_n(text.begin(), text.size(), it); | |
269 | ctx.advance_to(output); | |
270 | } break; | |
271 | ||
272 | case format_part_t::which_value::argument_id: { | |
273 | advance_parse_context_to_specification(parse_ctx, part); | |
274 | format_arg<Range>(parse_ctx, ctx, value.arg_id); | |
275 | } break; | |
276 | ||
277 | case format_part_t::which_value::named_argument_id: { | |
278 | advance_parse_context_to_specification(parse_ctx, part); | |
279 | const auto named_arg_id = value.named_arg_id.to_view(format_view); | |
280 | format_arg<Range>(parse_ctx, ctx, named_arg_id); | |
281 | } break; | |
282 | case format_part_t::which_value::specification: { | |
283 | const auto& arg_id_value = value.spec.arg_id.val; | |
284 | const auto arg = | |
285 | value.spec.arg_id.which == | |
286 | format_part_t::argument_id::which_arg_id::index | |
287 | ? ctx.arg(arg_id_value.index) | |
288 | : ctx.arg(arg_id_value.named_index.to_view(format_)); | |
289 | ||
290 | auto specs = value.spec.parsed_specs; | |
291 | ||
292 | handle_dynamic_spec<internal::width_checker>( | |
293 | specs.width_, specs.width_ref, ctx, format_view.begin()); | |
294 | handle_dynamic_spec<internal::precision_checker>( | |
295 | specs.precision, specs.precision_ref, ctx, format_view.begin()); | |
296 | ||
297 | check_prepared_specs(specs, arg.type()); | |
298 | advance_parse_context_to_specification(parse_ctx, part); | |
299 | ctx.advance_to( | |
300 | visit_format_arg(arg_formatter<Range>(ctx, FMT_NULL, &specs), arg)); | |
301 | } break; | |
302 | } | |
303 | } | |
304 | ||
305 | return ctx.out(); | |
306 | } | |
307 | ||
308 | void advance_parse_context_to_specification( | |
309 | basic_parse_context<char_type>& parse_ctx, | |
310 | const format_part_t& part) const { | |
311 | const auto view = to_string_view(format_); | |
312 | const auto specification_begin = view.data() + part.end_of_argument_id; | |
313 | parse_ctx.advance_to(specification_begin); | |
314 | } | |
315 | ||
316 | template <typename Range, typename Context, typename Id> | |
317 | void format_arg(basic_parse_context<char_type>& parse_ctx, Context& ctx, | |
318 | Id arg_id) const { | |
319 | parse_ctx.check_arg_id(arg_id); | |
320 | const auto stopped_at = | |
321 | visit_format_arg(arg_formatter<Range>(ctx), ctx.arg(arg_id)); | |
322 | ctx.advance_to(stopped_at); | |
323 | } | |
324 | ||
325 | template <typename Char> | |
326 | void check_prepared_specs(const basic_format_specs<Char>& specs, | |
327 | internal::type arg_type) const { | |
328 | internal::error_handler h; | |
329 | numeric_specs_checker<internal::error_handler> checker(h, arg_type); | |
330 | if (specs.align_ == ALIGN_NUMERIC) { | |
331 | checker.require_numeric_argument(); | |
332 | } | |
333 | ||
334 | if (specs.has(PLUS_FLAG | MINUS_FLAG | SIGN_FLAG)) { | |
335 | checker.check_sign(); | |
336 | } | |
337 | ||
338 | if (specs.has(HASH_FLAG)) { | |
339 | checker.require_numeric_argument(); | |
340 | } | |
341 | ||
342 | if (specs.has_precision()) { | |
343 | checker.check_precision(); | |
344 | } | |
345 | } | |
346 | ||
347 | private: | |
348 | Format format_; | |
349 | PreparedPartsProvider parts_provider_; | |
350 | }; | |
351 | ||
352 | template <typename Format> class compiletime_prepared_parts_type_provider { | |
353 | private: | |
354 | typedef FMT_CHAR(Format) char_type; | |
355 | ||
356 | class count_handler { | |
357 | private: | |
358 | typedef internal::null_terminating_iterator<char_type> iterator; | |
359 | ||
360 | public: | |
361 | FMT_CONSTEXPR count_handler() : counter_(0u) {} | |
362 | ||
363 | FMT_CONSTEXPR void on_text(const char_type* begin, const char_type* end) { | |
364 | if (begin != end) { | |
365 | ++counter_; | |
366 | } | |
367 | } | |
368 | ||
369 | FMT_CONSTEXPR void on_arg_id() { ++counter_; } | |
370 | FMT_CONSTEXPR void on_arg_id(unsigned) { ++counter_; } | |
371 | FMT_CONSTEXPR void on_arg_id(basic_string_view<char_type>) { ++counter_; } | |
372 | ||
373 | FMT_CONSTEXPR void on_replacement_field(const char_type*) {} | |
374 | ||
375 | FMT_CONSTEXPR const char_type* on_format_specs(const char_type* begin, | |
376 | const char_type* end) { | |
377 | return find_matching_brace(begin, end); | |
378 | } | |
379 | ||
380 | FMT_CONSTEXPR void on_error(const char*) {} | |
381 | ||
382 | FMT_CONSTEXPR unsigned result() const { return counter_; } | |
383 | ||
384 | private: | |
385 | FMT_CONSTEXPR const char_type* find_matching_brace(const char_type* begin, | |
386 | const char_type* end) { | |
387 | unsigned braces_counter{0u}; | |
388 | for (; begin != end; ++begin) { | |
389 | if (*begin == '{') { | |
390 | ++braces_counter; | |
391 | } else if (*begin == '}') { | |
392 | if (braces_counter == 0u) { | |
393 | break; | |
394 | } | |
395 | --braces_counter; | |
396 | } | |
397 | } | |
398 | ||
399 | return begin; | |
400 | } | |
401 | ||
402 | private: | |
403 | unsigned counter_; | |
404 | }; | |
405 | ||
406 | static FMT_CONSTEXPR unsigned count_parts() { | |
407 | FMT_CONSTEXPR_DECL const auto text = to_string_view(Format{}); | |
408 | count_handler handler; | |
409 | internal::parse_format_string</*IS_CONSTEXPR=*/true>(text, handler); | |
410 | return handler.result(); | |
411 | } | |
412 | ||
413 | // Workaround for old compilers. Compiletime parts preparation will not be | |
414 | // performed with them anyway. | |
415 | #if FMT_USE_CONSTEXPR | |
416 | static FMT_CONSTEXPR_DECL const unsigned number_of_format_parts = | |
417 | compiletime_prepared_parts_type_provider::count_parts(); | |
418 | #else | |
419 | static const unsigned number_of_format_parts = 0u; | |
420 | #endif | |
421 | ||
422 | public: | |
423 | template <unsigned N> struct format_parts_array { | |
424 | typedef format_part<char_type> value_type; | |
425 | ||
426 | FMT_CONSTEXPR format_parts_array() : arr{} {} | |
427 | ||
428 | FMT_CONSTEXPR value_type& operator[](unsigned ind) { return arr[ind]; } | |
429 | ||
430 | FMT_CONSTEXPR const value_type* begin() const { return arr; } | |
431 | ||
432 | FMT_CONSTEXPR const value_type* end() const { return begin() + N; } | |
433 | ||
434 | private: | |
435 | value_type arr[N]; | |
436 | }; | |
437 | ||
438 | struct empty { | |
439 | // Parts preparator will search for it | |
440 | typedef format_part<char_type> value_type; | |
441 | }; | |
442 | ||
443 | typedef typename std::conditional<static_cast<bool>(number_of_format_parts), | |
444 | format_parts_array<number_of_format_parts>, | |
445 | empty>::type type; | |
446 | }; | |
447 | ||
448 | template <typename Parts> class compiletime_prepared_parts_collector { | |
449 | private: | |
450 | typedef typename Parts::value_type format_part; | |
451 | ||
452 | public: | |
453 | FMT_CONSTEXPR explicit compiletime_prepared_parts_collector(Parts& parts) | |
454 | : parts_{parts}, counter_{0u} {} | |
455 | ||
456 | FMT_CONSTEXPR void add(format_part part) { parts_[counter_++] = part; } | |
457 | ||
458 | FMT_CONSTEXPR void substitute_last(format_part part) { | |
459 | parts_[counter_ - 1] = part; | |
460 | } | |
461 | ||
462 | FMT_CONSTEXPR format_part last() { return parts_[counter_ - 1]; } | |
463 | ||
464 | private: | |
465 | Parts& parts_; | |
466 | unsigned counter_; | |
467 | }; | |
468 | ||
469 | template <typename PartsContainer, typename Char> | |
470 | FMT_CONSTEXPR PartsContainer prepare_parts(basic_string_view<Char> format) { | |
471 | PartsContainer parts; | |
472 | internal::parse_format_string</*IS_CONSTEXPR=*/false>( | |
473 | format, format_preparation_handler<Char, PartsContainer>(format, parts)); | |
474 | return parts; | |
475 | } | |
476 | ||
477 | template <typename PartsContainer, typename Char> | |
478 | FMT_CONSTEXPR PartsContainer | |
479 | prepare_compiletime_parts(basic_string_view<Char> format) { | |
480 | typedef compiletime_prepared_parts_collector<PartsContainer> collector; | |
481 | ||
482 | PartsContainer parts; | |
483 | collector c(parts); | |
484 | internal::parse_format_string</*IS_CONSTEXPR=*/true>( | |
485 | format, format_preparation_handler<Char, collector>(format, c)); | |
486 | return parts; | |
487 | } | |
488 | ||
489 | template <typename PartsContainer> class runtime_parts_provider { | |
490 | public: | |
491 | runtime_parts_provider() = delete; | |
492 | template <typename Char> | |
493 | runtime_parts_provider(basic_string_view<Char> format) | |
494 | : parts_(prepare_parts<PartsContainer>(format)) {} | |
495 | ||
496 | const PartsContainer& parts() const { return parts_; } | |
497 | ||
498 | private: | |
499 | PartsContainer parts_; | |
500 | }; | |
501 | ||
502 | template <typename Format, typename PartsContainer> | |
503 | struct compiletime_parts_provider { | |
504 | compiletime_parts_provider() = delete; | |
505 | template <typename Char> | |
506 | FMT_CONSTEXPR compiletime_parts_provider(basic_string_view<Char>) {} | |
507 | ||
508 | const PartsContainer& parts() const { | |
509 | static FMT_CONSTEXPR_DECL const PartsContainer prepared_parts = | |
510 | prepare_compiletime_parts<PartsContainer>( | |
511 | internal::to_string_view(Format{})); | |
512 | ||
513 | return prepared_parts; | |
514 | } | |
515 | }; | |
516 | ||
517 | template <typename PartsContainer> | |
518 | struct parts_container_concept_check : std::true_type { | |
519 | #if FMT_HAS_CONSTRUCTIBLE_TRAITS | |
520 | static_assert(std::is_copy_constructible<PartsContainer>::value, | |
521 | "PartsContainer is not copy constructible"); | |
522 | static_assert(std::is_move_constructible<PartsContainer>::value, | |
523 | "PartsContainer is not move constructible"); | |
524 | #endif | |
525 | ||
526 | template <typename T, typename = void> | |
527 | struct has_format_part_type : std::false_type {}; | |
528 | template <typename T> | |
529 | struct has_format_part_type< | |
530 | T, typename void_<typename T::format_part_type>::type> : std::true_type { | |
531 | }; | |
532 | ||
533 | static_assert(has_format_part_type<PartsContainer>::value, | |
534 | "PartsContainer doesn't provide format_part_type typedef"); | |
535 | ||
536 | struct check_second {}; | |
537 | struct check_first : check_second {}; | |
538 | ||
539 | template <typename T> static std::false_type has_add_check(check_second); | |
540 | template <typename T> | |
541 | static decltype( | |
542 | (void)declval<T>().add(declval<typename T::format_part_type>()), | |
543 | std::true_type()) has_add_check(check_first); | |
544 | typedef decltype(has_add_check<PartsContainer>(check_first())) has_add; | |
545 | static_assert(has_add::value, "PartsContainer doesn't provide add() method"); | |
546 | ||
547 | template <typename T> static std::false_type has_last_check(check_second); | |
548 | template <typename T> | |
549 | static decltype((void)declval<T>().last(), | |
550 | std::true_type()) has_last_check(check_first); | |
551 | typedef decltype(has_last_check<PartsContainer>(check_first())) has_last; | |
552 | static_assert(has_last::value, | |
553 | "PartsContainer doesn't provide last() method"); | |
554 | ||
555 | template <typename T> | |
556 | static std::false_type has_substitute_last_check(check_second); | |
557 | template <typename T> | |
558 | static decltype((void)declval<T>().substitute_last( | |
559 | declval<typename T::format_part_type>()), | |
560 | std::true_type()) has_substitute_last_check(check_first); | |
561 | typedef decltype(has_substitute_last_check<PartsContainer>( | |
562 | check_first())) has_substitute_last; | |
563 | static_assert(has_substitute_last::value, | |
564 | "PartsContainer doesn't provide substitute_last() method"); | |
565 | ||
566 | template <typename T> static std::false_type has_begin_check(check_second); | |
567 | template <typename T> | |
568 | static decltype((void)declval<T>().begin(), | |
569 | std::true_type()) has_begin_check(check_first); | |
570 | typedef decltype(has_begin_check<PartsContainer>(check_first())) has_begin; | |
571 | static_assert(has_begin::value, | |
572 | "PartsContainer doesn't provide begin() method"); | |
573 | ||
574 | template <typename T> static std::false_type has_end_check(check_second); | |
575 | template <typename T> | |
576 | static decltype((void)declval<T>().end(), | |
577 | std::true_type()) has_end_check(check_first); | |
578 | typedef decltype(has_end_check<PartsContainer>(check_first())) has_end; | |
579 | static_assert(has_end::value, "PartsContainer doesn't provide end() method"); | |
580 | }; | |
581 | ||
582 | template <bool IS_CONSTEXPR, typename Format, typename /*PartsContainer*/> | |
583 | struct parts_provider_type { | |
584 | typedef compiletime_parts_provider< | |
585 | Format, typename compiletime_prepared_parts_type_provider<Format>::type> | |
586 | type; | |
587 | }; | |
588 | ||
589 | template <typename Format, typename PartsContainer> | |
590 | struct parts_provider_type</*IS_CONSTEXPR=*/false, Format, PartsContainer> { | |
591 | static_assert(parts_container_concept_check<PartsContainer>::value, | |
592 | "Parts container doesn't meet the concept"); | |
593 | typedef runtime_parts_provider<PartsContainer> type; | |
594 | }; | |
595 | ||
596 | template <typename Format, typename PreparedPartsContainer, typename... Args> | |
597 | struct basic_prepared_format { | |
598 | typedef internal::prepared_format<Format, | |
599 | typename internal::parts_provider_type< | |
600 | is_compile_string<Format>::value, | |
601 | Format, PreparedPartsContainer>::type, | |
602 | Args...> | |
603 | type; | |
604 | }; | |
605 | ||
606 | template <typename Char> | |
607 | std::basic_string<Char> to_runtime_format(basic_string_view<Char> format) { | |
608 | return std::basic_string<Char>(format.begin(), format.size()); | |
609 | } | |
610 | ||
611 | template <typename Char> | |
612 | std::basic_string<Char> to_runtime_format(const Char* format) { | |
613 | return std::basic_string<Char>(format); | |
614 | } | |
615 | ||
616 | template <typename Char, typename Container = std::vector<format_part<Char>>> | |
617 | class parts_container { | |
618 | public: | |
619 | typedef format_part<Char> format_part_type; | |
620 | ||
621 | void add(format_part_type part) { parts_.push_back(std::move(part)); } | |
622 | ||
623 | void substitute_last(format_part_type part) { | |
624 | parts_.back() = std::move(part); | |
625 | } | |
626 | ||
627 | format_part_type last() { return parts_.back(); } | |
628 | ||
629 | auto begin() -> decltype(internal::declval<Container>().begin()) { | |
630 | return parts_.begin(); | |
631 | } | |
632 | ||
633 | auto begin() const -> decltype(internal::declval<const Container>().begin()) { | |
634 | return parts_.begin(); | |
635 | } | |
636 | ||
637 | auto end() -> decltype(internal::declval<Container>().end()) { | |
638 | return parts_.end(); | |
639 | } | |
640 | ||
641 | auto end() const -> decltype(internal::declval<const Container>().end()) { | |
642 | return parts_.end(); | |
643 | } | |
644 | ||
645 | private: | |
646 | Container parts_; | |
647 | }; | |
648 | ||
649 | // Delegate preparing to preparator, to take advantage of a partial | |
650 | // specialization. | |
651 | template <typename Format, typename... Args> struct preparator { | |
652 | typedef parts_container<FMT_CHAR(Format)> container; | |
653 | typedef typename basic_prepared_format<Format, container, Args...>::type | |
654 | prepared_format_type; | |
655 | ||
656 | static auto prepare(Format format) -> prepared_format_type { | |
657 | return prepared_format_type(std::move(format)); | |
658 | } | |
659 | }; | |
660 | ||
661 | template <typename PassedFormat, typename PreparedFormatFormat, | |
662 | typename PartsContainer, typename... Args> | |
663 | struct preparator<PassedFormat, prepared_format<PreparedFormatFormat, | |
664 | PartsContainer, Args...>> { | |
665 | typedef prepared_format<PreparedFormatFormat, PartsContainer, Args...> | |
666 | prepared_format_type; | |
667 | ||
668 | static auto prepare(PassedFormat format) -> prepared_format_type { | |
669 | return prepared_format_type(std::move(format)); | |
670 | } | |
671 | }; | |
672 | ||
673 | struct compiletime_format_tag {}; | |
674 | struct runtime_format_tag {}; | |
675 | ||
676 | template <typename Format> struct format_tag { | |
677 | typedef typename std::conditional<is_compile_string<Format>::value, | |
678 | compiletime_format_tag, | |
679 | runtime_format_tag>::type type; | |
680 | }; | |
681 | ||
682 | #if FMT_USE_CONSTEXPR | |
683 | template <typename Format, typename... Args> | |
684 | auto do_prepare(runtime_format_tag, Format format) { | |
685 | return preparator<Format, Args...>::prepare(std::move(format)); | |
686 | } | |
687 | ||
688 | template <typename Format, typename... Args> | |
689 | FMT_CONSTEXPR auto do_prepare(compiletime_format_tag, const Format& format) { | |
690 | return typename basic_prepared_format<Format, void, Args...>::type(format); | |
691 | } | |
692 | #else | |
693 | template <typename Format, typename... Args> | |
694 | auto do_prepare(const Format& format) | |
695 | -> decltype(preparator<Format, Args...>::prepare(format)) { | |
696 | return preparator<Format, Args...>::prepare(format); | |
697 | } | |
698 | #endif | |
699 | } // namespace internal | |
700 | ||
701 | template <typename Char, typename Container = std::vector<format_part<Char>>> | |
702 | struct parts_container { | |
703 | typedef internal::parts_container<Char, Container> type; | |
704 | }; | |
705 | ||
706 | template <typename Format, typename PartsContainer, typename... Args> | |
707 | struct basic_prepared_format { | |
708 | typedef typename internal::basic_prepared_format<Format, PartsContainer, | |
709 | Args...>::type type; | |
710 | }; | |
711 | ||
712 | template <typename... Args> struct prepared_format { | |
713 | typedef typename basic_prepared_format< | |
714 | std::string, typename parts_container<char>::type, Args...>::type type; | |
715 | }; | |
716 | ||
717 | template <typename... Args> struct wprepared_format { | |
718 | typedef | |
719 | typename basic_prepared_format<std::wstring, | |
720 | typename parts_container<wchar_t>::type, | |
721 | Args...>::type type; | |
722 | }; | |
723 | ||
724 | #if FMT_USE_ALIAS_TEMPLATES | |
725 | ||
726 | template <typename Char, typename Container = std::vector<format_part<Char>>> | |
727 | using parts_container_t = typename parts_container<Char, Container>::type; | |
728 | ||
729 | template <typename Format, typename PreparedPartsContainer, typename... Args> | |
730 | using basic_prepared_format_t = | |
731 | typename basic_prepared_format<Format, PreparedPartsContainer, | |
732 | Args...>::type; | |
733 | ||
734 | template <typename... Args> | |
735 | using prepared_format_t = | |
736 | basic_prepared_format_t<std::string, parts_container<char>, Args...>; | |
737 | ||
738 | template <typename... Args> | |
739 | using wprepared_format_t = | |
740 | basic_prepared_format_t<std::wstring, parts_container<wchar_t>, Args...>; | |
741 | ||
742 | #endif | |
743 | ||
744 | #if FMT_USE_CONSTEXPR | |
745 | ||
746 | template <typename... Args, typename Format> | |
747 | FMT_CONSTEXPR auto prepare(Format format) { | |
748 | return internal::do_prepare<Format, Args...>( | |
749 | typename internal::format_tag<Format>::type{}, std::move(format)); | |
750 | } | |
751 | #else | |
752 | ||
753 | template <typename... Args, typename Format> | |
754 | auto prepare(Format format) -> | |
755 | typename internal::preparator<Format, Args...>::prepared_format_type { | |
756 | return internal::preparator<Format, Args...>::prepare(std::move(format)); | |
757 | } | |
758 | #endif | |
759 | ||
760 | template <typename... Args, typename Char> | |
761 | auto prepare(const Char* format) -> | |
762 | typename internal::preparator<std::basic_string<Char>, | |
763 | Args...>::prepared_format_type { | |
764 | return prepare<Args...>(internal::to_runtime_format(format)); | |
765 | } | |
766 | ||
767 | template <typename... Args, typename Char, unsigned N> | |
768 | auto prepare(const Char(format)[N]) -> | |
769 | typename internal::preparator<std::basic_string<Char>, | |
770 | Args...>::prepared_format_type { | |
771 | const auto view = basic_string_view<Char>(format, N); | |
772 | return prepare<Args...>(internal::to_runtime_format(view)); | |
773 | } | |
774 | ||
775 | template <typename... Args, typename Char> | |
776 | auto prepare(basic_string_view<Char> format) -> | |
777 | typename internal::preparator<std::basic_string<Char>, | |
778 | Args...>::prepared_format_type { | |
779 | return prepare<Args...>(internal::to_runtime_format(format)); | |
780 | } | |
781 | ||
782 | FMT_END_NAMESPACE | |
783 | ||
784 | #endif // FMT_PREPARE_H_ |