1 | // Formatting library for C++ - the core API |
---|
2 | // |
---|
3 | // Copyright (c) 2012 - present, Victor Zverovich |
---|
4 | // All rights reserved. |
---|
5 | // |
---|
6 | // For the license information refer to format.h. |
---|
7 | |
---|
8 | #ifndef FMT_CORE_H_ |
---|
9 | #define FMT_CORE_H_ |
---|
10 | |
---|
11 | #include <cassert> |
---|
12 | #include <cstdio> // std::FILE |
---|
13 | #include <cstring> |
---|
14 | #include <iterator> |
---|
15 | #include <string> |
---|
16 | #include <type_traits> |
---|
17 | |
---|
18 | // The fmt library version in the form major * 10000 + minor * 100 + patch. |
---|
19 | #define FMT_VERSION 50300 |
---|
20 | |
---|
21 | #ifdef __has_feature |
---|
22 | # define FMT_HAS_FEATURE(x) __has_feature(x) |
---|
23 | #else |
---|
24 | # define FMT_HAS_FEATURE(x) 0 |
---|
25 | #endif |
---|
26 | |
---|
27 | #if defined(__has_include) && !defined(__INTELLISENSE__) && \ |
---|
28 | !(defined(__INTEL_COMPILER) && __INTEL_COMPILER < 1600) |
---|
29 | # define FMT_HAS_INCLUDE(x) __has_include(x) |
---|
30 | #else |
---|
31 | # define FMT_HAS_INCLUDE(x) 0 |
---|
32 | #endif |
---|
33 | |
---|
34 | #ifdef __has_cpp_attribute |
---|
35 | # define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) |
---|
36 | #else |
---|
37 | # define FMT_HAS_CPP_ATTRIBUTE(x) 0 |
---|
38 | #endif |
---|
39 | |
---|
40 | #if defined(__GNUC__) && !defined(__clang__) |
---|
41 | # define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) |
---|
42 | #else |
---|
43 | # define FMT_GCC_VERSION 0 |
---|
44 | #endif |
---|
45 | |
---|
46 | #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) |
---|
47 | # define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION |
---|
48 | #else |
---|
49 | # define FMT_HAS_GXX_CXX11 0 |
---|
50 | #endif |
---|
51 | |
---|
52 | #ifdef _MSC_VER |
---|
53 | # define FMT_MSC_VER _MSC_VER |
---|
54 | #else |
---|
55 | # define FMT_MSC_VER 0 |
---|
56 | #endif |
---|
57 | |
---|
58 | // Check if relaxed C++14 constexpr is supported. |
---|
59 | // GCC doesn't allow throw in constexpr until version 6 (bug 67371). |
---|
60 | #ifndef FMT_USE_CONSTEXPR |
---|
61 | # define FMT_USE_CONSTEXPR \ |
---|
62 | (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \ |
---|
63 | (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) |
---|
64 | #endif |
---|
65 | #if FMT_USE_CONSTEXPR |
---|
66 | # define FMT_CONSTEXPR constexpr |
---|
67 | # define FMT_CONSTEXPR_DECL constexpr |
---|
68 | #else |
---|
69 | # define FMT_CONSTEXPR inline |
---|
70 | # define FMT_CONSTEXPR_DECL |
---|
71 | #endif |
---|
72 | |
---|
73 | #ifndef FMT_USE_CONSTEXPR11 |
---|
74 | # define FMT_USE_CONSTEXPR11 \ |
---|
75 | (FMT_USE_CONSTEXPR || FMT_GCC_VERSION >= 406 || FMT_MSC_VER >= 1900) |
---|
76 | #endif |
---|
77 | #if FMT_USE_CONSTEXPR11 |
---|
78 | # define FMT_CONSTEXPR11 constexpr |
---|
79 | #else |
---|
80 | # define FMT_CONSTEXPR11 |
---|
81 | #endif |
---|
82 | |
---|
83 | #ifndef FMT_OVERRIDE |
---|
84 | # if FMT_HAS_FEATURE(cxx_override) || \ |
---|
85 | (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 |
---|
86 | # define FMT_OVERRIDE override |
---|
87 | # else |
---|
88 | # define FMT_OVERRIDE |
---|
89 | # endif |
---|
90 | #endif |
---|
91 | |
---|
92 | #if FMT_HAS_FEATURE(cxx_explicit_conversions) || \ |
---|
93 | FMT_GCC_VERSION >= 405 || FMT_MSC_VER >= 1800 |
---|
94 | # define FMT_USE_EXPLICIT 1 |
---|
95 | # define FMT_EXPLICIT explicit |
---|
96 | #else |
---|
97 | # define FMT_USE_EXPLICIT 0 |
---|
98 | # define FMT_EXPLICIT |
---|
99 | #endif |
---|
100 | |
---|
101 | #ifndef FMT_NULL |
---|
102 | # if FMT_HAS_FEATURE(cxx_nullptr) || \ |
---|
103 | (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600 |
---|
104 | # define FMT_NULL nullptr |
---|
105 | # define FMT_USE_NULLPTR 1 |
---|
106 | # else |
---|
107 | # define FMT_NULL NULL |
---|
108 | # endif |
---|
109 | #endif |
---|
110 | #ifndef FMT_USE_NULLPTR |
---|
111 | # define FMT_USE_NULLPTR 0 |
---|
112 | #endif |
---|
113 | |
---|
114 | // Check if exceptions are disabled. |
---|
115 | #ifndef FMT_EXCEPTIONS |
---|
116 | # if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \ |
---|
117 | FMT_MSC_VER && !_HAS_EXCEPTIONS |
---|
118 | # define FMT_EXCEPTIONS 0 |
---|
119 | # else |
---|
120 | # define FMT_EXCEPTIONS 1 |
---|
121 | # endif |
---|
122 | #endif |
---|
123 | |
---|
124 | // Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature). |
---|
125 | #ifndef FMT_USE_NOEXCEPT |
---|
126 | # define FMT_USE_NOEXCEPT 0 |
---|
127 | #endif |
---|
128 | |
---|
129 | #if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ |
---|
130 | (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 |
---|
131 | # define FMT_DETECTED_NOEXCEPT noexcept |
---|
132 | # define FMT_HAS_CXX11_NOEXCEPT 1 |
---|
133 | #else |
---|
134 | # define FMT_DETECTED_NOEXCEPT throw() |
---|
135 | # define FMT_HAS_CXX11_NOEXCEPT 0 |
---|
136 | #endif |
---|
137 | |
---|
138 | #ifndef FMT_NOEXCEPT |
---|
139 | # if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT |
---|
140 | # define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT |
---|
141 | # else |
---|
142 | # define FMT_NOEXCEPT |
---|
143 | # endif |
---|
144 | #endif |
---|
145 | |
---|
146 | #ifndef FMT_BEGIN_NAMESPACE |
---|
147 | # if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \ |
---|
148 | FMT_MSC_VER >= 1900 |
---|
149 | # define FMT_INLINE_NAMESPACE inline namespace |
---|
150 | # define FMT_END_NAMESPACE }} |
---|
151 | # else |
---|
152 | # define FMT_INLINE_NAMESPACE namespace |
---|
153 | # define FMT_END_NAMESPACE } using namespace v5; } |
---|
154 | # endif |
---|
155 | # define FMT_BEGIN_NAMESPACE namespace fmt { FMT_INLINE_NAMESPACE v5 { |
---|
156 | #endif |
---|
157 | |
---|
158 | #if !defined(FMT_HEADER_ONLY) && defined(_WIN32) |
---|
159 | # ifdef FMT_EXPORT |
---|
160 | # define FMT_API __declspec(dllexport) |
---|
161 | # elif defined(FMT_SHARED) |
---|
162 | # define FMT_API __declspec(dllimport) |
---|
163 | # endif |
---|
164 | #endif |
---|
165 | #ifndef FMT_API |
---|
166 | # define FMT_API |
---|
167 | #endif |
---|
168 | |
---|
169 | #ifndef FMT_ASSERT |
---|
170 | # define FMT_ASSERT(condition, message) assert((condition) && message) |
---|
171 | #endif |
---|
172 | |
---|
173 | // libc++ supports string_view in pre-c++17. |
---|
174 | #if (FMT_HAS_INCLUDE(<string_view>) && \ |
---|
175 | (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \ |
---|
176 | (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) |
---|
177 | # include <string_view> |
---|
178 | # define FMT_STRING_VIEW std::basic_string_view |
---|
179 | #elif FMT_HAS_INCLUDE(<experimental/string_view>) && __cplusplus >= 201402L |
---|
180 | # include <experimental/string_view> |
---|
181 | # define FMT_STRING_VIEW std::experimental::basic_string_view |
---|
182 | #endif |
---|
183 | |
---|
184 | // std::result_of is defined in <functional> in gcc 4.4. |
---|
185 | #if FMT_GCC_VERSION && FMT_GCC_VERSION <= 404 |
---|
186 | # include <functional> |
---|
187 | #endif |
---|
188 | |
---|
189 | FMT_BEGIN_NAMESPACE |
---|
190 | namespace internal { |
---|
191 | |
---|
192 | // An implementation of declval for pre-C++11 compilers such as gcc 4. |
---|
193 | template <typename T> |
---|
194 | typename std::add_rvalue_reference<T>::type declval() FMT_NOEXCEPT; |
---|
195 | |
---|
196 | template <typename> |
---|
197 | struct result_of; |
---|
198 | |
---|
199 | template <typename F, typename... Args> |
---|
200 | struct result_of<F(Args...)> { |
---|
201 | // A workaround for gcc 4.4 that doesn't allow F to be a reference. |
---|
202 | typedef typename std::result_of< |
---|
203 | typename std::remove_reference<F>::type(Args...)>::type type; |
---|
204 | }; |
---|
205 | |
---|
206 | // Casts nonnegative integer to unsigned. |
---|
207 | template <typename Int> |
---|
208 | FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) { |
---|
209 | FMT_ASSERT(value >= 0, "negative value"); |
---|
210 | return static_cast<typename std::make_unsigned<Int>::type>(value); |
---|
211 | } |
---|
212 | |
---|
213 | /** A contiguous memory buffer with an optional growing ability. */ |
---|
214 | template <typename T> |
---|
215 | class basic_buffer { |
---|
216 | private: |
---|
217 | basic_buffer(const basic_buffer &) = delete; |
---|
218 | void operator=(const basic_buffer &) = delete; |
---|
219 | |
---|
220 | T *ptr_; |
---|
221 | std::size_t size_; |
---|
222 | std::size_t capacity_; |
---|
223 | |
---|
224 | protected: |
---|
225 | // Don't initialize ptr_ since it is not accessed to save a few cycles. |
---|
226 | basic_buffer(std::size_t sz) FMT_NOEXCEPT: size_(sz), capacity_(sz) {} |
---|
227 | |
---|
228 | basic_buffer(T *p = FMT_NULL, std::size_t sz = 0, std::size_t cap = 0) |
---|
229 | FMT_NOEXCEPT: ptr_(p), size_(sz), capacity_(cap) {} |
---|
230 | |
---|
231 | /** Sets the buffer data and capacity. */ |
---|
232 | void set(T *buf_data, std::size_t buf_capacity) FMT_NOEXCEPT { |
---|
233 | ptr_ = buf_data; |
---|
234 | capacity_ = buf_capacity; |
---|
235 | } |
---|
236 | |
---|
237 | /** Increases the buffer capacity to hold at least *capacity* elements. */ |
---|
238 | virtual void grow(std::size_t capacity) = 0; |
---|
239 | |
---|
240 | public: |
---|
241 | typedef T value_type; |
---|
242 | typedef const T &const_reference; |
---|
243 | |
---|
244 | virtual ~basic_buffer() {} |
---|
245 | |
---|
246 | T *begin() FMT_NOEXCEPT { return ptr_; } |
---|
247 | T *end() FMT_NOEXCEPT { return ptr_ + size_; } |
---|
248 | |
---|
249 | /** Returns the size of this buffer. */ |
---|
250 | std::size_t size() const FMT_NOEXCEPT { return size_; } |
---|
251 | |
---|
252 | /** Returns the capacity of this buffer. */ |
---|
253 | std::size_t capacity() const FMT_NOEXCEPT { return capacity_; } |
---|
254 | |
---|
255 | /** Returns a pointer to the buffer data. */ |
---|
256 | T *data() FMT_NOEXCEPT { return ptr_; } |
---|
257 | |
---|
258 | /** Returns a pointer to the buffer data. */ |
---|
259 | const T *data() const FMT_NOEXCEPT { return ptr_; } |
---|
260 | |
---|
261 | /** |
---|
262 | Resizes the buffer. If T is a POD type new elements may not be initialized. |
---|
263 | */ |
---|
264 | void resize(std::size_t new_size) { |
---|
265 | reserve(new_size); |
---|
266 | size_ = new_size; |
---|
267 | } |
---|
268 | |
---|
269 | /** Clears this buffer. */ |
---|
270 | void clear() { size_ = 0; } |
---|
271 | |
---|
272 | /** Reserves space to store at least *capacity* elements. */ |
---|
273 | void reserve(std::size_t new_capacity) { |
---|
274 | if (new_capacity > capacity_) |
---|
275 | grow(new_capacity); |
---|
276 | } |
---|
277 | |
---|
278 | void push_back(const T &value) { |
---|
279 | reserve(size_ + 1); |
---|
280 | ptr_[size_++] = value; |
---|
281 | } |
---|
282 | |
---|
283 | /** Appends data to the end of the buffer. */ |
---|
284 | template <typename U> |
---|
285 | void append(const U *begin, const U *end); |
---|
286 | |
---|
287 | T &operator[](std::size_t index) { return ptr_[index]; } |
---|
288 | const T &operator[](std::size_t index) const { return ptr_[index]; } |
---|
289 | }; |
---|
290 | |
---|
291 | typedef basic_buffer<char> buffer; |
---|
292 | typedef basic_buffer<wchar_t> wbuffer; |
---|
293 | |
---|
294 | // A container-backed buffer. |
---|
295 | template <typename Container> |
---|
296 | class container_buffer : public basic_buffer<typename Container::value_type> { |
---|
297 | private: |
---|
298 | Container &container_; |
---|
299 | |
---|
300 | protected: |
---|
301 | void grow(std::size_t capacity) FMT_OVERRIDE { |
---|
302 | container_.resize(capacity); |
---|
303 | this->set(&container_[0], capacity); |
---|
304 | } |
---|
305 | |
---|
306 | public: |
---|
307 | explicit container_buffer(Container &c) |
---|
308 | : basic_buffer<typename Container::value_type>(c.size()), container_(c) {} |
---|
309 | }; |
---|
310 | |
---|
311 | // Extracts a reference to the container from back_insert_iterator. |
---|
312 | template <typename Container> |
---|
313 | inline Container &get_container(std::back_insert_iterator<Container> it) { |
---|
314 | typedef std::back_insert_iterator<Container> bi_iterator; |
---|
315 | struct accessor: bi_iterator { |
---|
316 | accessor(bi_iterator iter) : bi_iterator(iter) {} |
---|
317 | using bi_iterator::container; |
---|
318 | }; |
---|
319 | return *accessor(it).container; |
---|
320 | } |
---|
321 | |
---|
322 | struct error_handler { |
---|
323 | FMT_CONSTEXPR error_handler() {} |
---|
324 | FMT_CONSTEXPR error_handler(const error_handler &) {} |
---|
325 | |
---|
326 | // This function is intentionally not constexpr to give a compile-time error. |
---|
327 | FMT_API void on_error(const char *message); |
---|
328 | }; |
---|
329 | |
---|
330 | template <typename T> |
---|
331 | struct no_formatter_error : std::false_type {}; |
---|
332 | } // namespace internal |
---|
333 | |
---|
334 | #if FMT_GCC_VERSION && FMT_GCC_VERSION < 405 |
---|
335 | template <typename... T> |
---|
336 | struct is_constructible: std::false_type {}; |
---|
337 | #else |
---|
338 | template <typename... T> |
---|
339 | struct is_constructible : std::is_constructible<T...> {}; |
---|
340 | #endif |
---|
341 | |
---|
342 | /** |
---|
343 | An implementation of ``std::basic_string_view`` for pre-C++17. It provides a |
---|
344 | subset of the API. ``fmt::basic_string_view`` is used for format strings even |
---|
345 | if ``std::string_view`` is available to prevent issues when a library is |
---|
346 | compiled with a different ``-std`` option than the client code (which is not |
---|
347 | recommended). |
---|
348 | */ |
---|
349 | template <typename Char> |
---|
350 | class basic_string_view { |
---|
351 | private: |
---|
352 | const Char *data_; |
---|
353 | size_t size_; |
---|
354 | |
---|
355 | public: |
---|
356 | typedef Char char_type; |
---|
357 | typedef const Char *iterator; |
---|
358 | |
---|
359 | FMT_CONSTEXPR basic_string_view() FMT_NOEXCEPT : data_(FMT_NULL), size_(0) {} |
---|
360 | |
---|
361 | /** Constructs a string reference object from a C string and a size. */ |
---|
362 | FMT_CONSTEXPR basic_string_view(const Char *s, size_t count) FMT_NOEXCEPT |
---|
363 | : data_(s), size_(count) {} |
---|
364 | |
---|
365 | /** |
---|
366 | \rst |
---|
367 | Constructs a string reference object from a C string computing |
---|
368 | the size with ``std::char_traits<Char>::length``. |
---|
369 | \endrst |
---|
370 | */ |
---|
371 | basic_string_view(const Char *s) |
---|
372 | : data_(s), size_(std::char_traits<Char>::length(s)) {} |
---|
373 | |
---|
374 | /** Constructs a string reference from a ``std::basic_string`` object. */ |
---|
375 | template <typename Alloc> |
---|
376 | FMT_CONSTEXPR basic_string_view( |
---|
377 | const std::basic_string<Char, Alloc> &s) FMT_NOEXCEPT |
---|
378 | : data_(s.data()), size_(s.size()) {} |
---|
379 | |
---|
380 | #ifdef FMT_STRING_VIEW |
---|
381 | FMT_CONSTEXPR basic_string_view(FMT_STRING_VIEW<Char> s) FMT_NOEXCEPT |
---|
382 | : data_(s.data()), size_(s.size()) {} |
---|
383 | #endif |
---|
384 | |
---|
385 | /** Returns a pointer to the string data. */ |
---|
386 | FMT_CONSTEXPR const Char *data() const { return data_; } |
---|
387 | |
---|
388 | /** Returns the string size. */ |
---|
389 | FMT_CONSTEXPR size_t size() const { return size_; } |
---|
390 | |
---|
391 | FMT_CONSTEXPR iterator begin() const { return data_; } |
---|
392 | FMT_CONSTEXPR iterator end() const { return data_ + size_; } |
---|
393 | |
---|
394 | FMT_CONSTEXPR void remove_prefix(size_t n) { |
---|
395 | data_ += n; |
---|
396 | size_ -= n; |
---|
397 | } |
---|
398 | |
---|
399 | // Lexicographically compare this string reference to other. |
---|
400 | int compare(basic_string_view other) const { |
---|
401 | size_t str_size = size_ < other.size_ ? size_ : other.size_; |
---|
402 | int result = std::char_traits<Char>::compare(data_, other.data_, str_size); |
---|
403 | if (result == 0) |
---|
404 | result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); |
---|
405 | return result; |
---|
406 | } |
---|
407 | |
---|
408 | friend bool operator==(basic_string_view lhs, basic_string_view rhs) { |
---|
409 | return lhs.compare(rhs) == 0; |
---|
410 | } |
---|
411 | friend bool operator!=(basic_string_view lhs, basic_string_view rhs) { |
---|
412 | return lhs.compare(rhs) != 0; |
---|
413 | } |
---|
414 | friend bool operator<(basic_string_view lhs, basic_string_view rhs) { |
---|
415 | return lhs.compare(rhs) < 0; |
---|
416 | } |
---|
417 | friend bool operator<=(basic_string_view lhs, basic_string_view rhs) { |
---|
418 | return lhs.compare(rhs) <= 0; |
---|
419 | } |
---|
420 | friend bool operator>(basic_string_view lhs, basic_string_view rhs) { |
---|
421 | return lhs.compare(rhs) > 0; |
---|
422 | } |
---|
423 | friend bool operator>=(basic_string_view lhs, basic_string_view rhs) { |
---|
424 | return lhs.compare(rhs) >= 0; |
---|
425 | } |
---|
426 | }; |
---|
427 | |
---|
428 | typedef basic_string_view<char> string_view; |
---|
429 | typedef basic_string_view<wchar_t> wstring_view; |
---|
430 | |
---|
431 | /** |
---|
432 | \rst |
---|
433 | The function ``to_string_view`` adapts non-intrusively any kind of string or |
---|
434 | string-like type if the user provides a (possibly templated) overload of |
---|
435 | ``to_string_view`` which takes an instance of the string class |
---|
436 | ``StringType<Char>`` and returns a ``fmt::basic_string_view<Char>``. |
---|
437 | The conversion function must live in the very same namespace as |
---|
438 | ``StringType<Char>`` to be picked up by ADL. Non-templated string types |
---|
439 | like f.e. QString must return a ``basic_string_view`` with a fixed matching |
---|
440 | char type. |
---|
441 | |
---|
442 | **Example**:: |
---|
443 | |
---|
444 | namespace my_ns { |
---|
445 | inline string_view to_string_view(const my_string &s) { |
---|
446 | return {s.data(), s.length()}; |
---|
447 | } |
---|
448 | } |
---|
449 | |
---|
450 | std::string message = fmt::format(my_string("The answer is {}"), 42); |
---|
451 | \endrst |
---|
452 | */ |
---|
453 | template <typename Char> |
---|
454 | inline basic_string_view<Char> |
---|
455 | to_string_view(basic_string_view<Char> s) { return s; } |
---|
456 | |
---|
457 | template <typename Char> |
---|
458 | inline basic_string_view<Char> |
---|
459 | to_string_view(const std::basic_string<Char> &s) { return s; } |
---|
460 | |
---|
461 | template <typename Char> |
---|
462 | inline basic_string_view<Char> to_string_view(const Char *s) { return s; } |
---|
463 | |
---|
464 | #ifdef FMT_STRING_VIEW |
---|
465 | template <typename Char> |
---|
466 | inline basic_string_view<Char> |
---|
467 | to_string_view(FMT_STRING_VIEW<Char> s) { return s; } |
---|
468 | #endif |
---|
469 | |
---|
470 | // A base class for compile-time strings. It is defined in the fmt namespace to |
---|
471 | // make formatting functions visible via ADL, e.g. format(fmt("{}"), 42). |
---|
472 | struct compile_string {}; |
---|
473 | |
---|
474 | template <typename S> |
---|
475 | struct is_compile_string : std::is_base_of<compile_string, S> {}; |
---|
476 | |
---|
477 | template < |
---|
478 | typename S, |
---|
479 | typename Enable = typename std::enable_if<is_compile_string<S>::value>::type> |
---|
480 | FMT_CONSTEXPR basic_string_view<typename S::char_type> |
---|
481 | to_string_view(const S &s) { return s; } |
---|
482 | |
---|
483 | template <typename Context> |
---|
484 | class basic_format_arg; |
---|
485 | |
---|
486 | template <typename Context> |
---|
487 | class basic_format_args; |
---|
488 | |
---|
489 | // A formatter for objects of type T. |
---|
490 | template <typename T, typename Char = char, typename Enable = void> |
---|
491 | struct formatter { |
---|
492 | static_assert(internal::no_formatter_error<T>::value, |
---|
493 | "don't know how to format the type, include fmt/ostream.h if it provides " |
---|
494 | "an operator<< that should be used"); |
---|
495 | |
---|
496 | // The following functions are not defined intentionally. |
---|
497 | template <typename ParseContext> |
---|
498 | typename ParseContext::iterator parse(ParseContext &); |
---|
499 | template <typename FormatContext> |
---|
500 | auto format(const T &val, FormatContext &ctx) -> decltype(ctx.out()); |
---|
501 | }; |
---|
502 | |
---|
503 | template <typename T, typename Char, typename Enable = void> |
---|
504 | struct convert_to_int: std::integral_constant< |
---|
505 | bool, !std::is_arithmetic<T>::value && std::is_convertible<T, int>::value> {}; |
---|
506 | |
---|
507 | namespace internal { |
---|
508 | |
---|
509 | struct dummy_string_view { typedef void char_type; }; |
---|
510 | dummy_string_view to_string_view(...); |
---|
511 | using fmt::v5::to_string_view; |
---|
512 | |
---|
513 | // Specifies whether S is a string type convertible to fmt::basic_string_view. |
---|
514 | template <typename S> |
---|
515 | struct is_string : std::integral_constant<bool, !std::is_same< |
---|
516 | dummy_string_view, decltype(to_string_view(declval<S>()))>::value> {}; |
---|
517 | |
---|
518 | template <typename S> |
---|
519 | struct char_t { |
---|
520 | typedef decltype(to_string_view(declval<S>())) result; |
---|
521 | typedef typename result::char_type type; |
---|
522 | }; |
---|
523 | |
---|
524 | template <typename Char> |
---|
525 | struct named_arg_base; |
---|
526 | |
---|
527 | template <typename T, typename Char> |
---|
528 | struct named_arg; |
---|
529 | |
---|
530 | enum type { |
---|
531 | none_type, named_arg_type, |
---|
532 | // Integer types should go first, |
---|
533 | int_type, uint_type, long_long_type, ulong_long_type, bool_type, char_type, |
---|
534 | last_integer_type = char_type, |
---|
535 | // followed by floating-point types. |
---|
536 | double_type, long_double_type, last_numeric_type = long_double_type, |
---|
537 | cstring_type, string_type, pointer_type, custom_type |
---|
538 | }; |
---|
539 | |
---|
540 | FMT_CONSTEXPR bool is_integral(type t) { |
---|
541 | FMT_ASSERT(t != internal::named_arg_type, "invalid argument type"); |
---|
542 | return t > internal::none_type && t <= internal::last_integer_type; |
---|
543 | } |
---|
544 | |
---|
545 | FMT_CONSTEXPR bool is_arithmetic(type t) { |
---|
546 | FMT_ASSERT(t != internal::named_arg_type, "invalid argument type"); |
---|
547 | return t > internal::none_type && t <= internal::last_numeric_type; |
---|
548 | } |
---|
549 | |
---|
550 | template <typename Char> |
---|
551 | struct string_value { |
---|
552 | const Char *value; |
---|
553 | std::size_t size; |
---|
554 | }; |
---|
555 | |
---|
556 | template <typename Context> |
---|
557 | struct custom_value { |
---|
558 | const void *value; |
---|
559 | void (*format)(const void *arg, Context &ctx); |
---|
560 | }; |
---|
561 | |
---|
562 | // A formatting argument value. |
---|
563 | template <typename Context> |
---|
564 | class value { |
---|
565 | public: |
---|
566 | typedef typename Context::char_type char_type; |
---|
567 | |
---|
568 | union { |
---|
569 | int int_value; |
---|
570 | unsigned uint_value; |
---|
571 | long long long_long_value; |
---|
572 | unsigned long long ulong_long_value; |
---|
573 | double double_value; |
---|
574 | long double long_double_value; |
---|
575 | const void *pointer; |
---|
576 | string_value<char_type> string; |
---|
577 | string_value<signed char> sstring; |
---|
578 | string_value<unsigned char> ustring; |
---|
579 | custom_value<Context> custom; |
---|
580 | }; |
---|
581 | |
---|
582 | FMT_CONSTEXPR value(int val = 0) : int_value(val) {} |
---|
583 | value(unsigned val) { uint_value = val; } |
---|
584 | value(long long val) { long_long_value = val; } |
---|
585 | value(unsigned long long val) { ulong_long_value = val; } |
---|
586 | value(double val) { double_value = val; } |
---|
587 | value(long double val) { long_double_value = val; } |
---|
588 | value(const char_type *val) { string.value = val; } |
---|
589 | value(const signed char *val) { |
---|
590 | static_assert(std::is_same<char, char_type>::value, |
---|
591 | "incompatible string types"); |
---|
592 | sstring.value = val; |
---|
593 | } |
---|
594 | value(const unsigned char *val) { |
---|
595 | static_assert(std::is_same<char, char_type>::value, |
---|
596 | "incompatible string types"); |
---|
597 | ustring.value = val; |
---|
598 | } |
---|
599 | value(basic_string_view<char_type> val) { |
---|
600 | string.value = val.data(); |
---|
601 | string.size = val.size(); |
---|
602 | } |
---|
603 | value(const void *val) { pointer = val; } |
---|
604 | |
---|
605 | template <typename T> |
---|
606 | explicit value(const T &val) { |
---|
607 | custom.value = &val; |
---|
608 | custom.format = &format_custom_arg<T>; |
---|
609 | } |
---|
610 | |
---|
611 | const named_arg_base<char_type> &as_named_arg() { |
---|
612 | return *static_cast<const named_arg_base<char_type>*>(pointer); |
---|
613 | } |
---|
614 | |
---|
615 | private: |
---|
616 | // Formats an argument of a custom type, such as a user-defined class. |
---|
617 | template <typename T> |
---|
618 | static void format_custom_arg(const void *arg, Context &ctx) { |
---|
619 | // Get the formatter type through the context to allow different contexts |
---|
620 | // have different extension points, e.g. `formatter<T>` for `format` and |
---|
621 | // `printf_formatter<T>` for `printf`. |
---|
622 | typename Context::template formatter_type<T>::type f; |
---|
623 | auto &&parse_ctx = ctx.parse_context(); |
---|
624 | parse_ctx.advance_to(f.parse(parse_ctx)); |
---|
625 | ctx.advance_to(f.format(*static_cast<const T*>(arg), ctx)); |
---|
626 | } |
---|
627 | }; |
---|
628 | |
---|
629 | // Value initializer used to delay conversion to value and reduce memory churn. |
---|
630 | template <typename Context, typename T, type TYPE> |
---|
631 | struct init { |
---|
632 | T val; |
---|
633 | static const type type_tag = TYPE; |
---|
634 | |
---|
635 | FMT_CONSTEXPR init(const T &v) : val(v) {} |
---|
636 | FMT_CONSTEXPR operator value<Context>() const { return value<Context>(val); } |
---|
637 | }; |
---|
638 | |
---|
639 | template <typename Context, typename T> |
---|
640 | FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T &value); |
---|
641 | |
---|
642 | #define FMT_MAKE_VALUE(TAG, ArgType, ValueType) \ |
---|
643 | template <typename C> \ |
---|
644 | FMT_CONSTEXPR init<C, ValueType, TAG> make_value(ArgType val) { \ |
---|
645 | return static_cast<ValueType>(val); \ |
---|
646 | } |
---|
647 | |
---|
648 | #define FMT_MAKE_VALUE_SAME(TAG, Type) \ |
---|
649 | template <typename C> \ |
---|
650 | FMT_CONSTEXPR init<C, Type, TAG> make_value(Type val) { return val; } |
---|
651 | |
---|
652 | FMT_MAKE_VALUE(bool_type, bool, int) |
---|
653 | FMT_MAKE_VALUE(int_type, short, int) |
---|
654 | FMT_MAKE_VALUE(uint_type, unsigned short, unsigned) |
---|
655 | FMT_MAKE_VALUE_SAME(int_type, int) |
---|
656 | FMT_MAKE_VALUE_SAME(uint_type, unsigned) |
---|
657 | |
---|
658 | // To minimize the number of types we need to deal with, long is translated |
---|
659 | // either to int or to long long depending on its size. |
---|
660 | typedef std::conditional<sizeof(long) == sizeof(int), int, long long>::type |
---|
661 | long_type; |
---|
662 | FMT_MAKE_VALUE( |
---|
663 | (sizeof(long) == sizeof(int) ? int_type : long_long_type), long, long_type) |
---|
664 | typedef std::conditional<sizeof(unsigned long) == sizeof(unsigned), |
---|
665 | unsigned, unsigned long long>::type ulong_type; |
---|
666 | FMT_MAKE_VALUE( |
---|
667 | (sizeof(unsigned long) == sizeof(unsigned) ? uint_type : ulong_long_type), |
---|
668 | unsigned long, ulong_type) |
---|
669 | |
---|
670 | FMT_MAKE_VALUE_SAME(long_long_type, long long) |
---|
671 | FMT_MAKE_VALUE_SAME(ulong_long_type, unsigned long long) |
---|
672 | FMT_MAKE_VALUE(int_type, signed char, int) |
---|
673 | FMT_MAKE_VALUE(uint_type, unsigned char, unsigned) |
---|
674 | |
---|
675 | // This doesn't use FMT_MAKE_VALUE because of ambiguity in gcc 4.4. |
---|
676 | template <typename C, typename Char> |
---|
677 | FMT_CONSTEXPR typename std::enable_if< |
---|
678 | std::is_same<typename C::char_type, Char>::value, |
---|
679 | init<C, int, char_type>>::type make_value(Char val) { return val; } |
---|
680 | |
---|
681 | template <typename C> |
---|
682 | FMT_CONSTEXPR typename std::enable_if< |
---|
683 | !std::is_same<typename C::char_type, char>::value, |
---|
684 | init<C, int, char_type>>::type make_value(char val) { return val; } |
---|
685 | |
---|
686 | FMT_MAKE_VALUE(double_type, float, double) |
---|
687 | FMT_MAKE_VALUE_SAME(double_type, double) |
---|
688 | FMT_MAKE_VALUE_SAME(long_double_type, long double) |
---|
689 | |
---|
690 | // Formatting of wide strings into a narrow buffer and multibyte strings |
---|
691 | // into a wide buffer is disallowed (https://github.com/fmtlib/fmt/pull/606). |
---|
692 | FMT_MAKE_VALUE(cstring_type, typename C::char_type*, |
---|
693 | const typename C::char_type*) |
---|
694 | FMT_MAKE_VALUE(cstring_type, const typename C::char_type*, |
---|
695 | const typename C::char_type*) |
---|
696 | |
---|
697 | FMT_MAKE_VALUE(cstring_type, signed char*, const signed char*) |
---|
698 | FMT_MAKE_VALUE_SAME(cstring_type, const signed char*) |
---|
699 | FMT_MAKE_VALUE(cstring_type, unsigned char*, const unsigned char*) |
---|
700 | FMT_MAKE_VALUE_SAME(cstring_type, const unsigned char*) |
---|
701 | FMT_MAKE_VALUE_SAME(string_type, basic_string_view<typename C::char_type>) |
---|
702 | FMT_MAKE_VALUE(string_type, |
---|
703 | typename basic_string_view<typename C::char_type>::type, |
---|
704 | basic_string_view<typename C::char_type>) |
---|
705 | FMT_MAKE_VALUE(string_type, const std::basic_string<typename C::char_type>&, |
---|
706 | basic_string_view<typename C::char_type>) |
---|
707 | FMT_MAKE_VALUE(pointer_type, void*, const void*) |
---|
708 | FMT_MAKE_VALUE_SAME(pointer_type, const void*) |
---|
709 | |
---|
710 | #if FMT_USE_NULLPTR |
---|
711 | FMT_MAKE_VALUE(pointer_type, std::nullptr_t, const void*) |
---|
712 | #endif |
---|
713 | |
---|
714 | // Formatting of arbitrary pointers is disallowed. If you want to output a |
---|
715 | // pointer cast it to "void *" or "const void *". In particular, this forbids |
---|
716 | // formatting of "[const] volatile char *" which is printed as bool by |
---|
717 | // iostreams. |
---|
718 | template <typename C, typename T> |
---|
719 | typename std::enable_if<!std::is_same<T, typename C::char_type>::value>::type |
---|
720 | make_value(const T *) { |
---|
721 | static_assert(!sizeof(T), "formatting of non-void pointers is disallowed"); |
---|
722 | } |
---|
723 | |
---|
724 | template <typename C, typename T> |
---|
725 | inline typename std::enable_if< |
---|
726 | std::is_enum<T>::value && convert_to_int<T, typename C::char_type>::value, |
---|
727 | init<C, int, int_type>>::type |
---|
728 | make_value(const T &val) { return static_cast<int>(val); } |
---|
729 | |
---|
730 | template <typename C, typename T, typename Char = typename C::char_type> |
---|
731 | inline typename std::enable_if< |
---|
732 | is_constructible<basic_string_view<Char>, T>::value && |
---|
733 | !internal::is_string<T>::value, |
---|
734 | init<C, basic_string_view<Char>, string_type>>::type |
---|
735 | make_value(const T &val) { return basic_string_view<Char>(val); } |
---|
736 | |
---|
737 | template <typename C, typename T, typename Char = typename C::char_type> |
---|
738 | inline typename std::enable_if< |
---|
739 | !convert_to_int<T, Char>::value && !std::is_same<T, Char>::value && |
---|
740 | !std::is_convertible<T, basic_string_view<Char>>::value && |
---|
741 | !is_constructible<basic_string_view<Char>, T>::value && |
---|
742 | !internal::is_string<T>::value, |
---|
743 | // Implicit conversion to std::string is not handled here because it's |
---|
744 | // unsafe: https://github.com/fmtlib/fmt/issues/729 |
---|
745 | init<C, const T &, custom_type>>::type |
---|
746 | make_value(const T &val) { return val; } |
---|
747 | |
---|
748 | template <typename C, typename T> |
---|
749 | init<C, const void*, named_arg_type> |
---|
750 | make_value(const named_arg<T, typename C::char_type> &val) { |
---|
751 | basic_format_arg<C> arg = make_arg<C>(val.value); |
---|
752 | std::memcpy(val.data, &arg, sizeof(arg)); |
---|
753 | return static_cast<const void*>(&val); |
---|
754 | } |
---|
755 | |
---|
756 | template <typename C, typename S> |
---|
757 | FMT_CONSTEXPR11 typename std::enable_if< |
---|
758 | internal::is_string<S>::value, |
---|
759 | init<C, basic_string_view<typename C::char_type>, string_type>>::type |
---|
760 | make_value(const S &val) { |
---|
761 | // Handle adapted strings. |
---|
762 | static_assert(std::is_same< |
---|
763 | typename C::char_type, typename internal::char_t<S>::type>::value, |
---|
764 | "mismatch between char-types of context and argument"); |
---|
765 | return to_string_view(val); |
---|
766 | } |
---|
767 | |
---|
768 | // Maximum number of arguments with packed types. |
---|
769 | enum { max_packed_args = 15 }; |
---|
770 | enum : unsigned long long { is_unpacked_bit = 1ull << 63 }; |
---|
771 | |
---|
772 | template <typename Context> |
---|
773 | class arg_map; |
---|
774 | } // namespace internal |
---|
775 | |
---|
776 | // A formatting argument. It is a trivially copyable/constructible type to |
---|
777 | // allow storage in basic_memory_buffer. |
---|
778 | template <typename Context> |
---|
779 | class basic_format_arg { |
---|
780 | private: |
---|
781 | internal::value<Context> value_; |
---|
782 | internal::type type_; |
---|
783 | |
---|
784 | template <typename ContextType, typename T> |
---|
785 | friend FMT_CONSTEXPR basic_format_arg<ContextType> |
---|
786 | internal::make_arg(const T &value); |
---|
787 | |
---|
788 | template <typename Visitor, typename Ctx> |
---|
789 | friend FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type |
---|
790 | visit_format_arg(Visitor &&vis, const basic_format_arg<Ctx> &arg); |
---|
791 | |
---|
792 | friend class basic_format_args<Context>; |
---|
793 | friend class internal::arg_map<Context>; |
---|
794 | |
---|
795 | typedef typename Context::char_type char_type; |
---|
796 | |
---|
797 | public: |
---|
798 | class handle { |
---|
799 | public: |
---|
800 | explicit handle(internal::custom_value<Context> custom): custom_(custom) {} |
---|
801 | |
---|
802 | void format(Context &ctx) const { custom_.format(custom_.value, ctx); } |
---|
803 | |
---|
804 | private: |
---|
805 | internal::custom_value<Context> custom_; |
---|
806 | }; |
---|
807 | |
---|
808 | FMT_CONSTEXPR basic_format_arg() : type_(internal::none_type) {} |
---|
809 | |
---|
810 | FMT_EXPLICIT operator bool() const FMT_NOEXCEPT { |
---|
811 | return type_ != internal::none_type; |
---|
812 | } |
---|
813 | |
---|
814 | internal::type type() const { return type_; } |
---|
815 | |
---|
816 | bool is_integral() const { return internal::is_integral(type_); } |
---|
817 | bool is_arithmetic() const { return internal::is_arithmetic(type_); } |
---|
818 | }; |
---|
819 | |
---|
820 | struct monostate {}; |
---|
821 | |
---|
822 | /** |
---|
823 | \rst |
---|
824 | Visits an argument dispatching to the appropriate visit method based on |
---|
825 | the argument type. For example, if the argument type is ``double`` then |
---|
826 | ``vis(value)`` will be called with the value of type ``double``. |
---|
827 | \endrst |
---|
828 | */ |
---|
829 | template <typename Visitor, typename Context> |
---|
830 | FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type |
---|
831 | visit_format_arg(Visitor &&vis, const basic_format_arg<Context> &arg) { |
---|
832 | typedef typename Context::char_type char_type; |
---|
833 | switch (arg.type_) { |
---|
834 | case internal::none_type: |
---|
835 | break; |
---|
836 | case internal::named_arg_type: |
---|
837 | FMT_ASSERT(false, "invalid argument type"); |
---|
838 | break; |
---|
839 | case internal::int_type: |
---|
840 | return vis(arg.value_.int_value); |
---|
841 | case internal::uint_type: |
---|
842 | return vis(arg.value_.uint_value); |
---|
843 | case internal::long_long_type: |
---|
844 | return vis(arg.value_.long_long_value); |
---|
845 | case internal::ulong_long_type: |
---|
846 | return vis(arg.value_.ulong_long_value); |
---|
847 | case internal::bool_type: |
---|
848 | return vis(arg.value_.int_value != 0); |
---|
849 | case internal::char_type: |
---|
850 | return vis(static_cast<char_type>(arg.value_.int_value)); |
---|
851 | case internal::double_type: |
---|
852 | return vis(arg.value_.double_value); |
---|
853 | case internal::long_double_type: |
---|
854 | return vis(arg.value_.long_double_value); |
---|
855 | case internal::cstring_type: |
---|
856 | return vis(arg.value_.string.value); |
---|
857 | case internal::string_type: |
---|
858 | return vis(basic_string_view<char_type>( |
---|
859 | arg.value_.string.value, arg.value_.string.size)); |
---|
860 | case internal::pointer_type: |
---|
861 | return vis(arg.value_.pointer); |
---|
862 | case internal::custom_type: |
---|
863 | return vis(typename basic_format_arg<Context>::handle(arg.value_.custom)); |
---|
864 | } |
---|
865 | return vis(monostate()); |
---|
866 | } |
---|
867 | |
---|
868 | // DEPRECATED! |
---|
869 | template <typename Visitor, typename Context> |
---|
870 | FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type |
---|
871 | visit(Visitor &&vis, const basic_format_arg<Context> &arg) { |
---|
872 | return visit_format_arg(std::forward<Visitor>(vis), arg); |
---|
873 | } |
---|
874 | |
---|
875 | // Parsing context consisting of a format string range being parsed and an |
---|
876 | // argument counter for automatic indexing. |
---|
877 | template <typename Char, typename ErrorHandler = internal::error_handler> |
---|
878 | class basic_parse_context : private ErrorHandler { |
---|
879 | private: |
---|
880 | basic_string_view<Char> format_str_; |
---|
881 | int next_arg_id_; |
---|
882 | |
---|
883 | public: |
---|
884 | typedef Char char_type; |
---|
885 | typedef typename basic_string_view<Char>::iterator iterator; |
---|
886 | |
---|
887 | explicit FMT_CONSTEXPR basic_parse_context( |
---|
888 | basic_string_view<Char> format_str, ErrorHandler eh = ErrorHandler()) |
---|
889 | : ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {} |
---|
890 | |
---|
891 | // Returns an iterator to the beginning of the format string range being |
---|
892 | // parsed. |
---|
893 | FMT_CONSTEXPR iterator begin() const FMT_NOEXCEPT { |
---|
894 | return format_str_.begin(); |
---|
895 | } |
---|
896 | |
---|
897 | // Returns an iterator past the end of the format string range being parsed. |
---|
898 | FMT_CONSTEXPR iterator end() const FMT_NOEXCEPT { return format_str_.end(); } |
---|
899 | |
---|
900 | // Advances the begin iterator to ``it``. |
---|
901 | FMT_CONSTEXPR void advance_to(iterator it) { |
---|
902 | format_str_.remove_prefix(internal::to_unsigned(it - begin())); |
---|
903 | } |
---|
904 | |
---|
905 | // Returns the next argument index. |
---|
906 | FMT_CONSTEXPR unsigned next_arg_id(); |
---|
907 | |
---|
908 | FMT_CONSTEXPR bool check_arg_id(unsigned) { |
---|
909 | if (next_arg_id_ > 0) { |
---|
910 | on_error("cannot switch from automatic to manual argument indexing"); |
---|
911 | return false; |
---|
912 | } |
---|
913 | next_arg_id_ = -1; |
---|
914 | return true; |
---|
915 | } |
---|
916 | void check_arg_id(basic_string_view<Char>) {} |
---|
917 | |
---|
918 | FMT_CONSTEXPR void on_error(const char *message) { |
---|
919 | ErrorHandler::on_error(message); |
---|
920 | } |
---|
921 | |
---|
922 | FMT_CONSTEXPR ErrorHandler error_handler() const { return *this; } |
---|
923 | }; |
---|
924 | |
---|
925 | typedef basic_parse_context<char> format_parse_context; |
---|
926 | typedef basic_parse_context<wchar_t> wformat_parse_context; |
---|
927 | |
---|
928 | // DEPRECATED! |
---|
929 | typedef basic_parse_context<char> parse_context; |
---|
930 | typedef basic_parse_context<wchar_t> wparse_context; |
---|
931 | |
---|
932 | namespace internal { |
---|
933 | // A map from argument names to their values for named arguments. |
---|
934 | template <typename Context> |
---|
935 | class arg_map { |
---|
936 | private: |
---|
937 | arg_map(const arg_map &) = delete; |
---|
938 | void operator=(const arg_map &) = delete; |
---|
939 | |
---|
940 | typedef typename Context::char_type char_type; |
---|
941 | |
---|
942 | struct entry { |
---|
943 | basic_string_view<char_type> name; |
---|
944 | basic_format_arg<Context> arg; |
---|
945 | }; |
---|
946 | |
---|
947 | entry *map_; |
---|
948 | unsigned size_; |
---|
949 | |
---|
950 | void push_back(value<Context> val) { |
---|
951 | const internal::named_arg_base<char_type> &named = val.as_named_arg(); |
---|
952 | map_[size_] = entry{named.name, named.template deserialize<Context>()}; |
---|
953 | ++size_; |
---|
954 | } |
---|
955 | |
---|
956 | public: |
---|
957 | arg_map() : map_(FMT_NULL), size_(0) {} |
---|
958 | void init(const basic_format_args<Context> &args); |
---|
959 | ~arg_map() { delete [] map_; } |
---|
960 | |
---|
961 | basic_format_arg<Context> find(basic_string_view<char_type> name) const { |
---|
962 | // The list is unsorted, so just return the first matching name. |
---|
963 | for (entry *it = map_, *end = map_ + size_; it != end; ++it) { |
---|
964 | if (it->name == name) |
---|
965 | return it->arg; |
---|
966 | } |
---|
967 | return {}; |
---|
968 | } |
---|
969 | }; |
---|
970 | |
---|
971 | // A type-erased reference to an std::locale to avoid heavy <locale> include. |
---|
972 | class locale_ref { |
---|
973 | private: |
---|
974 | const void *locale_; // A type-erased pointer to std::locale. |
---|
975 | friend class locale; |
---|
976 | |
---|
977 | public: |
---|
978 | locale_ref() : locale_(FMT_NULL) {} |
---|
979 | |
---|
980 | template <typename Locale> |
---|
981 | explicit locale_ref(const Locale &loc); |
---|
982 | |
---|
983 | template <typename Locale> |
---|
984 | Locale get() const; |
---|
985 | }; |
---|
986 | |
---|
987 | template <typename OutputIt, typename Context, typename Char> |
---|
988 | class context_base { |
---|
989 | public: |
---|
990 | typedef OutputIt iterator; |
---|
991 | |
---|
992 | private: |
---|
993 | basic_parse_context<Char> parse_context_; |
---|
994 | iterator out_; |
---|
995 | basic_format_args<Context> args_; |
---|
996 | locale_ref loc_; |
---|
997 | |
---|
998 | protected: |
---|
999 | typedef Char char_type; |
---|
1000 | typedef basic_format_arg<Context> format_arg; |
---|
1001 | |
---|
1002 | context_base(OutputIt out, basic_string_view<char_type> format_str, |
---|
1003 | basic_format_args<Context> ctx_args, |
---|
1004 | locale_ref loc = locale_ref()) |
---|
1005 | : parse_context_(format_str), out_(out), args_(ctx_args), loc_(loc) {} |
---|
1006 | |
---|
1007 | // Returns the argument with specified index. |
---|
1008 | format_arg do_get_arg(unsigned arg_id) { |
---|
1009 | format_arg arg = args_.get(arg_id); |
---|
1010 | if (!arg) |
---|
1011 | parse_context_.on_error("argument index out of range"); |
---|
1012 | return arg; |
---|
1013 | } |
---|
1014 | |
---|
1015 | // Checks if manual indexing is used and returns the argument with |
---|
1016 | // specified index. |
---|
1017 | format_arg get_arg(unsigned arg_id) { |
---|
1018 | return this->parse_context().check_arg_id(arg_id) ? |
---|
1019 | this->do_get_arg(arg_id) : format_arg(); |
---|
1020 | } |
---|
1021 | |
---|
1022 | public: |
---|
1023 | basic_parse_context<char_type> &parse_context() { return parse_context_; } |
---|
1024 | basic_format_args<Context> args() const { return args_; } // DEPRECATED! |
---|
1025 | basic_format_arg<Context> arg(unsigned id) const { return args_.get(id); } |
---|
1026 | |
---|
1027 | internal::error_handler error_handler() { |
---|
1028 | return parse_context_.error_handler(); |
---|
1029 | } |
---|
1030 | |
---|
1031 | void on_error(const char *message) { parse_context_.on_error(message); } |
---|
1032 | |
---|
1033 | // Returns an iterator to the beginning of the output range. |
---|
1034 | iterator out() { return out_; } |
---|
1035 | iterator begin() { return out_; } // deprecated |
---|
1036 | |
---|
1037 | // Advances the begin iterator to ``it``. |
---|
1038 | void advance_to(iterator it) { out_ = it; } |
---|
1039 | |
---|
1040 | locale_ref locale() { return loc_; } |
---|
1041 | }; |
---|
1042 | |
---|
1043 | template <typename Context, typename T> |
---|
1044 | struct get_type { |
---|
1045 | typedef decltype(make_value<Context>( |
---|
1046 | declval<typename std::decay<T>::type&>())) value_type; |
---|
1047 | static const type value = value_type::type_tag; |
---|
1048 | }; |
---|
1049 | |
---|
1050 | template <typename Context> |
---|
1051 | FMT_CONSTEXPR11 unsigned long long get_types() { return 0; } |
---|
1052 | |
---|
1053 | template <typename Context, typename Arg, typename... Args> |
---|
1054 | FMT_CONSTEXPR11 unsigned long long get_types() { |
---|
1055 | return get_type<Context, Arg>::value | (get_types<Context, Args...>() << 4); |
---|
1056 | } |
---|
1057 | |
---|
1058 | template <typename Context, typename T> |
---|
1059 | FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T &value) { |
---|
1060 | basic_format_arg<Context> arg; |
---|
1061 | arg.type_ = get_type<Context, T>::value; |
---|
1062 | arg.value_ = make_value<Context>(value); |
---|
1063 | return arg; |
---|
1064 | } |
---|
1065 | |
---|
1066 | template <bool IS_PACKED, typename Context, typename T> |
---|
1067 | inline typename std::enable_if<IS_PACKED, value<Context>>::type |
---|
1068 | make_arg(const T &value) { |
---|
1069 | return make_value<Context>(value); |
---|
1070 | } |
---|
1071 | |
---|
1072 | template <bool IS_PACKED, typename Context, typename T> |
---|
1073 | inline typename std::enable_if<!IS_PACKED, basic_format_arg<Context>>::type |
---|
1074 | make_arg(const T &value) { |
---|
1075 | return make_arg<Context>(value); |
---|
1076 | } |
---|
1077 | } // namespace internal |
---|
1078 | |
---|
1079 | // Formatting context. |
---|
1080 | template <typename OutputIt, typename Char> |
---|
1081 | class basic_format_context : |
---|
1082 | public internal::context_base< |
---|
1083 | OutputIt, basic_format_context<OutputIt, Char>, Char> { |
---|
1084 | public: |
---|
1085 | /** The character type for the output. */ |
---|
1086 | typedef Char char_type; |
---|
1087 | |
---|
1088 | // using formatter_type = formatter<T, char_type>; |
---|
1089 | template <typename T> |
---|
1090 | struct formatter_type { typedef formatter<T, char_type> type; }; |
---|
1091 | |
---|
1092 | private: |
---|
1093 | internal::arg_map<basic_format_context> map_; |
---|
1094 | |
---|
1095 | basic_format_context(const basic_format_context &) = delete; |
---|
1096 | void operator=(const basic_format_context &) = delete; |
---|
1097 | |
---|
1098 | typedef internal::context_base<OutputIt, basic_format_context, Char> base; |
---|
1099 | typedef typename base::format_arg format_arg; |
---|
1100 | using base::get_arg; |
---|
1101 | |
---|
1102 | public: |
---|
1103 | using typename base::iterator; |
---|
1104 | |
---|
1105 | /** |
---|
1106 | Constructs a ``basic_format_context`` object. References to the arguments are |
---|
1107 | stored in the object so make sure they have appropriate lifetimes. |
---|
1108 | */ |
---|
1109 | basic_format_context(OutputIt out, basic_string_view<char_type> format_str, |
---|
1110 | basic_format_args<basic_format_context> ctx_args, |
---|
1111 | internal::locale_ref loc = internal::locale_ref()) |
---|
1112 | : base(out, format_str, ctx_args, loc) {} |
---|
1113 | |
---|
1114 | format_arg next_arg() { |
---|
1115 | return this->do_get_arg(this->parse_context().next_arg_id()); |
---|
1116 | } |
---|
1117 | format_arg get_arg(unsigned arg_id) { return this->do_get_arg(arg_id); } |
---|
1118 | |
---|
1119 | // Checks if manual indexing is used and returns the argument with the |
---|
1120 | // specified name. |
---|
1121 | format_arg get_arg(basic_string_view<char_type> name); |
---|
1122 | }; |
---|
1123 | |
---|
1124 | template <typename Char> |
---|
1125 | struct buffer_context { |
---|
1126 | typedef basic_format_context< |
---|
1127 | std::back_insert_iterator<internal::basic_buffer<Char>>, Char> type; |
---|
1128 | }; |
---|
1129 | typedef buffer_context<char>::type format_context; |
---|
1130 | typedef buffer_context<wchar_t>::type wformat_context; |
---|
1131 | |
---|
1132 | /** |
---|
1133 | \rst |
---|
1134 | An array of references to arguments. It can be implicitly converted into |
---|
1135 | `~fmt::basic_format_args` for passing into type-erased formatting functions |
---|
1136 | such as `~fmt::vformat`. |
---|
1137 | \endrst |
---|
1138 | */ |
---|
1139 | template <typename Context, typename ...Args> |
---|
1140 | class format_arg_store { |
---|
1141 | private: |
---|
1142 | static const size_t NUM_ARGS = sizeof...(Args); |
---|
1143 | |
---|
1144 | // Packed is a macro on MinGW so use IS_PACKED instead. |
---|
1145 | static const bool IS_PACKED = NUM_ARGS < internal::max_packed_args; |
---|
1146 | |
---|
1147 | typedef typename std::conditional<IS_PACKED, |
---|
1148 | internal::value<Context>, basic_format_arg<Context>>::type value_type; |
---|
1149 | |
---|
1150 | // If the arguments are not packed, add one more element to mark the end. |
---|
1151 | static const size_t DATA_SIZE = |
---|
1152 | NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1); |
---|
1153 | value_type data_[DATA_SIZE]; |
---|
1154 | |
---|
1155 | friend class basic_format_args<Context>; |
---|
1156 | |
---|
1157 | static FMT_CONSTEXPR11 unsigned long long get_types() { |
---|
1158 | return IS_PACKED ? |
---|
1159 | internal::get_types<Context, Args...>() : |
---|
1160 | internal::is_unpacked_bit | NUM_ARGS; |
---|
1161 | } |
---|
1162 | |
---|
1163 | public: |
---|
1164 | #if FMT_USE_CONSTEXPR11 |
---|
1165 | static FMT_CONSTEXPR11 unsigned long long TYPES = get_types(); |
---|
1166 | #else |
---|
1167 | static const unsigned long long TYPES; |
---|
1168 | #endif |
---|
1169 | |
---|
1170 | #if (FMT_GCC_VERSION && FMT_GCC_VERSION <= 405) || \ |
---|
1171 | (FMT_MSC_VER && FMT_MSC_VER <= 1800) |
---|
1172 | // Workaround array initialization issues in gcc <= 4.5 and MSVC <= 2013. |
---|
1173 | format_arg_store(const Args &... args) { |
---|
1174 | value_type init[DATA_SIZE] = |
---|
1175 | {internal::make_arg<IS_PACKED, Context>(args)...}; |
---|
1176 | std::memcpy(data_, init, sizeof(init)); |
---|
1177 | } |
---|
1178 | #else |
---|
1179 | format_arg_store(const Args &... args) |
---|
1180 | : data_{internal::make_arg<IS_PACKED, Context>(args)...} {} |
---|
1181 | #endif |
---|
1182 | }; |
---|
1183 | |
---|
1184 | #if !FMT_USE_CONSTEXPR11 |
---|
1185 | template <typename Context, typename ...Args> |
---|
1186 | const unsigned long long format_arg_store<Context, Args...>::TYPES = |
---|
1187 | get_types(); |
---|
1188 | #endif |
---|
1189 | |
---|
1190 | /** |
---|
1191 | \rst |
---|
1192 | Constructs an `~fmt::format_arg_store` object that contains references to |
---|
1193 | arguments and can be implicitly converted to `~fmt::format_args`. `Context` |
---|
1194 | can be omitted in which case it defaults to `~fmt::context`. |
---|
1195 | \endrst |
---|
1196 | */ |
---|
1197 | template <typename Context = format_context, typename ...Args> |
---|
1198 | inline format_arg_store<Context, Args...> |
---|
1199 | make_format_args(const Args &... args) { return {args...}; } |
---|
1200 | |
---|
1201 | /** Formatting arguments. */ |
---|
1202 | template <typename Context> |
---|
1203 | class basic_format_args { |
---|
1204 | public: |
---|
1205 | typedef unsigned size_type; |
---|
1206 | typedef basic_format_arg<Context> format_arg; |
---|
1207 | |
---|
1208 | private: |
---|
1209 | // To reduce compiled code size per formatting function call, types of first |
---|
1210 | // max_packed_args arguments are passed in the types_ field. |
---|
1211 | unsigned long long types_; |
---|
1212 | union { |
---|
1213 | // If the number of arguments is less than max_packed_args, the argument |
---|
1214 | // values are stored in values_, otherwise they are stored in args_. |
---|
1215 | // This is done to reduce compiled code size as storing larger objects |
---|
1216 | // may require more code (at least on x86-64) even if the same amount of |
---|
1217 | // data is actually copied to stack. It saves ~10% on the bloat test. |
---|
1218 | const internal::value<Context> *values_; |
---|
1219 | const format_arg *args_; |
---|
1220 | }; |
---|
1221 | |
---|
1222 | bool is_packed() const { return (types_ & internal::is_unpacked_bit) == 0; } |
---|
1223 | |
---|
1224 | typename internal::type type(unsigned index) const { |
---|
1225 | unsigned shift = index * 4; |
---|
1226 | return static_cast<typename internal::type>( |
---|
1227 | (types_ & (0xfull << shift)) >> shift); |
---|
1228 | } |
---|
1229 | |
---|
1230 | friend class internal::arg_map<Context>; |
---|
1231 | |
---|
1232 | void set_data(const internal::value<Context> *values) { values_ = values; } |
---|
1233 | void set_data(const format_arg *args) { args_ = args; } |
---|
1234 | |
---|
1235 | format_arg do_get(size_type index) const { |
---|
1236 | format_arg arg; |
---|
1237 | if (!is_packed()) { |
---|
1238 | auto num_args = max_size(); |
---|
1239 | if (index < num_args) |
---|
1240 | arg = args_[index]; |
---|
1241 | return arg; |
---|
1242 | } |
---|
1243 | if (index > internal::max_packed_args) |
---|
1244 | return arg; |
---|
1245 | arg.type_ = type(index); |
---|
1246 | if (arg.type_ == internal::none_type) |
---|
1247 | return arg; |
---|
1248 | internal::value<Context> &val = arg.value_; |
---|
1249 | val = values_[index]; |
---|
1250 | return arg; |
---|
1251 | } |
---|
1252 | |
---|
1253 | public: |
---|
1254 | basic_format_args() : types_(0) {} |
---|
1255 | |
---|
1256 | /** |
---|
1257 | \rst |
---|
1258 | Constructs a `basic_format_args` object from `~fmt::format_arg_store`. |
---|
1259 | \endrst |
---|
1260 | */ |
---|
1261 | template <typename... Args> |
---|
1262 | basic_format_args(const format_arg_store<Context, Args...> &store) |
---|
1263 | : types_(static_cast<unsigned long long>(store.TYPES)) { |
---|
1264 | set_data(store.data_); |
---|
1265 | } |
---|
1266 | |
---|
1267 | /** |
---|
1268 | \rst |
---|
1269 | Constructs a `basic_format_args` object from a dynamic set of arguments. |
---|
1270 | \endrst |
---|
1271 | */ |
---|
1272 | basic_format_args(const format_arg *args, size_type count) |
---|
1273 | : types_(internal::is_unpacked_bit | count) { |
---|
1274 | set_data(args); |
---|
1275 | } |
---|
1276 | |
---|
1277 | /** Returns the argument at specified index. */ |
---|
1278 | format_arg get(size_type index) const { |
---|
1279 | format_arg arg = do_get(index); |
---|
1280 | if (arg.type_ == internal::named_arg_type) |
---|
1281 | arg = arg.value_.as_named_arg().template deserialize<Context>(); |
---|
1282 | return arg; |
---|
1283 | } |
---|
1284 | |
---|
1285 | size_type max_size() const { |
---|
1286 | unsigned long long max_packed = internal::max_packed_args; |
---|
1287 | return static_cast<size_type>( |
---|
1288 | is_packed() ? max_packed : types_ & ~internal::is_unpacked_bit); |
---|
1289 | } |
---|
1290 | }; |
---|
1291 | |
---|
1292 | /** An alias to ``basic_format_args<context>``. */ |
---|
1293 | // It is a separate type rather than a typedef to make symbols readable. |
---|
1294 | struct format_args : basic_format_args<format_context> { |
---|
1295 | template <typename ...Args> |
---|
1296 | format_args(Args &&... arg) |
---|
1297 | : basic_format_args<format_context>(std::forward<Args>(arg)...) {} |
---|
1298 | }; |
---|
1299 | struct wformat_args : basic_format_args<wformat_context> { |
---|
1300 | template <typename ...Args> |
---|
1301 | wformat_args(Args &&... arg) |
---|
1302 | : basic_format_args<wformat_context>(std::forward<Args>(arg)...) {} |
---|
1303 | }; |
---|
1304 | |
---|
1305 | #define FMT_ENABLE_IF_T(B, T) typename std::enable_if<B, T>::type |
---|
1306 | |
---|
1307 | #ifndef FMT_USE_ALIAS_TEMPLATES |
---|
1308 | # define FMT_USE_ALIAS_TEMPLATES FMT_HAS_FEATURE(cxx_alias_templates) |
---|
1309 | #endif |
---|
1310 | #if FMT_USE_ALIAS_TEMPLATES |
---|
1311 | /** String's character type. */ |
---|
1312 | template <typename S> |
---|
1313 | using char_t = FMT_ENABLE_IF_T( |
---|
1314 | internal::is_string<S>::value, typename internal::char_t<S>::type); |
---|
1315 | #define FMT_CHAR(S) fmt::char_t<S> |
---|
1316 | #else |
---|
1317 | template <typename S> |
---|
1318 | struct char_t : std::enable_if< |
---|
1319 | internal::is_string<S>::value, typename internal::char_t<S>::type> {}; |
---|
1320 | #define FMT_CHAR(S) typename char_t<S>::type |
---|
1321 | #endif |
---|
1322 | |
---|
1323 | namespace internal { |
---|
1324 | template <typename Char> |
---|
1325 | struct named_arg_base { |
---|
1326 | basic_string_view<Char> name; |
---|
1327 | |
---|
1328 | // Serialized value<context>. |
---|
1329 | mutable char data[ |
---|
1330 | sizeof(basic_format_arg<typename buffer_context<Char>::type>)]; |
---|
1331 | |
---|
1332 | named_arg_base(basic_string_view<Char> nm) : name(nm) {} |
---|
1333 | |
---|
1334 | template <typename Context> |
---|
1335 | basic_format_arg<Context> deserialize() const { |
---|
1336 | basic_format_arg<Context> arg; |
---|
1337 | std::memcpy(&arg, data, sizeof(basic_format_arg<Context>)); |
---|
1338 | return arg; |
---|
1339 | } |
---|
1340 | }; |
---|
1341 | |
---|
1342 | template <typename T, typename Char> |
---|
1343 | struct named_arg : named_arg_base<Char> { |
---|
1344 | const T &value; |
---|
1345 | |
---|
1346 | named_arg(basic_string_view<Char> name, const T &val) |
---|
1347 | : named_arg_base<Char>(name), value(val) {} |
---|
1348 | }; |
---|
1349 | |
---|
1350 | template <typename... Args, typename S> |
---|
1351 | inline typename std::enable_if<!is_compile_string<S>::value>::type |
---|
1352 | check_format_string(const S &) {} |
---|
1353 | template <typename... Args, typename S> |
---|
1354 | typename std::enable_if<is_compile_string<S>::value>::type |
---|
1355 | check_format_string(S); |
---|
1356 | |
---|
1357 | template <typename S, typename... Args> |
---|
1358 | struct checked_args : format_arg_store< |
---|
1359 | typename buffer_context<FMT_CHAR(S)>::type, Args...> { |
---|
1360 | typedef typename buffer_context<FMT_CHAR(S)>::type context; |
---|
1361 | |
---|
1362 | checked_args(const S &format_str, const Args &... args): |
---|
1363 | format_arg_store<context, Args...>(args...) { |
---|
1364 | internal::check_format_string<Args...>(format_str); |
---|
1365 | } |
---|
1366 | |
---|
1367 | basic_format_args<context> operator*() const { return *this; } |
---|
1368 | }; |
---|
1369 | |
---|
1370 | template <typename Char> |
---|
1371 | std::basic_string<Char> vformat( |
---|
1372 | basic_string_view<Char> format_str, |
---|
1373 | basic_format_args<typename buffer_context<Char>::type> args); |
---|
1374 | |
---|
1375 | template <typename Char> |
---|
1376 | typename buffer_context<Char>::type::iterator vformat_to( |
---|
1377 | internal::basic_buffer<Char> &buf, basic_string_view<Char> format_str, |
---|
1378 | basic_format_args<typename buffer_context<Char>::type> args); |
---|
1379 | } |
---|
1380 | |
---|
1381 | /** |
---|
1382 | \rst |
---|
1383 | Returns a named argument to be used in a formatting function. |
---|
1384 | |
---|
1385 | **Example**:: |
---|
1386 | |
---|
1387 | fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)); |
---|
1388 | \endrst |
---|
1389 | */ |
---|
1390 | template <typename T> |
---|
1391 | inline internal::named_arg<T, char> arg(string_view name, const T &arg) { |
---|
1392 | return {name, arg}; |
---|
1393 | } |
---|
1394 | |
---|
1395 | template <typename T> |
---|
1396 | inline internal::named_arg<T, wchar_t> arg(wstring_view name, const T &arg) { |
---|
1397 | return {name, arg}; |
---|
1398 | } |
---|
1399 | |
---|
1400 | // Disable nested named arguments, e.g. ``arg("a", arg("b", 42))``. |
---|
1401 | template <typename S, typename T, typename Char> |
---|
1402 | void arg(S, internal::named_arg<T, Char>) = delete; |
---|
1403 | |
---|
1404 | template <typename Container> |
---|
1405 | struct is_contiguous: std::false_type {}; |
---|
1406 | |
---|
1407 | template <typename Char> |
---|
1408 | struct is_contiguous<std::basic_string<Char> >: std::true_type {}; |
---|
1409 | |
---|
1410 | template <typename Char> |
---|
1411 | struct is_contiguous<internal::basic_buffer<Char> >: std::true_type {}; |
---|
1412 | |
---|
1413 | /** Formats a string and writes the output to ``out``. */ |
---|
1414 | template <typename Container, typename S> |
---|
1415 | typename std::enable_if< |
---|
1416 | is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type |
---|
1417 | vformat_to( |
---|
1418 | std::back_insert_iterator<Container> out, |
---|
1419 | const S &format_str, |
---|
1420 | basic_format_args<typename buffer_context<FMT_CHAR(S)>::type> args) { |
---|
1421 | internal::container_buffer<Container> buf(internal::get_container(out)); |
---|
1422 | internal::vformat_to(buf, to_string_view(format_str), args); |
---|
1423 | return out; |
---|
1424 | } |
---|
1425 | |
---|
1426 | template <typename Container, typename S, typename... Args> |
---|
1427 | inline typename std::enable_if< |
---|
1428 | is_contiguous<Container>::value && internal::is_string<S>::value, |
---|
1429 | std::back_insert_iterator<Container>>::type |
---|
1430 | format_to(std::back_insert_iterator<Container> out, const S &format_str, |
---|
1431 | const Args &... args) { |
---|
1432 | internal::checked_args<S, Args...> ca(format_str, args...); |
---|
1433 | return vformat_to(out, to_string_view(format_str), *ca); |
---|
1434 | } |
---|
1435 | |
---|
1436 | template <typename S, typename Char = FMT_CHAR(S)> |
---|
1437 | inline std::basic_string<Char> vformat( |
---|
1438 | const S &format_str, |
---|
1439 | basic_format_args<typename buffer_context<Char>::type> args) { |
---|
1440 | return internal::vformat(to_string_view(format_str), args); |
---|
1441 | } |
---|
1442 | |
---|
1443 | /** |
---|
1444 | \rst |
---|
1445 | Formats arguments and returns the result as a string. |
---|
1446 | |
---|
1447 | **Example**:: |
---|
1448 | |
---|
1449 | #include <fmt/core.h> |
---|
1450 | std::string message = fmt::format("The answer is {}", 42); |
---|
1451 | \endrst |
---|
1452 | */ |
---|
1453 | template <typename S, typename... Args> |
---|
1454 | inline std::basic_string<FMT_CHAR(S)> format( |
---|
1455 | const S &format_str, const Args &... args) { |
---|
1456 | return internal::vformat( |
---|
1457 | to_string_view(format_str), |
---|
1458 | *internal::checked_args<S, Args...>(format_str, args...)); |
---|
1459 | } |
---|
1460 | |
---|
1461 | FMT_API void vprint(std::FILE *f, string_view format_str, format_args args); |
---|
1462 | FMT_API void vprint(std::FILE *f, wstring_view format_str, wformat_args args); |
---|
1463 | |
---|
1464 | /** |
---|
1465 | \rst |
---|
1466 | Prints formatted data to the file *f*. For wide format strings, |
---|
1467 | *f* should be in wide-oriented mode set via ``fwide(f, 1)`` or |
---|
1468 | ``_setmode(_fileno(f), _O_U8TEXT)`` on Windows. |
---|
1469 | |
---|
1470 | **Example**:: |
---|
1471 | |
---|
1472 | fmt::print(stderr, "Don't {}!", "panic"); |
---|
1473 | \endrst |
---|
1474 | */ |
---|
1475 | template <typename S, typename... Args> |
---|
1476 | inline FMT_ENABLE_IF_T(internal::is_string<S>::value, void) |
---|
1477 | print(std::FILE *f, const S &format_str, const Args &... args) { |
---|
1478 | vprint(f, to_string_view(format_str), |
---|
1479 | internal::checked_args<S, Args...>(format_str, args...)); |
---|
1480 | } |
---|
1481 | |
---|
1482 | FMT_API void vprint(string_view format_str, format_args args); |
---|
1483 | FMT_API void vprint(wstring_view format_str, wformat_args args); |
---|
1484 | |
---|
1485 | /** |
---|
1486 | \rst |
---|
1487 | Prints formatted data to ``stdout``. |
---|
1488 | |
---|
1489 | **Example**:: |
---|
1490 | |
---|
1491 | fmt::print("Elapsed time: {0:.2f} seconds", 1.23); |
---|
1492 | \endrst |
---|
1493 | */ |
---|
1494 | template <typename S, typename... Args> |
---|
1495 | inline FMT_ENABLE_IF_T(internal::is_string<S>::value, void) |
---|
1496 | print(const S &format_str, const Args &... args) { |
---|
1497 | vprint(to_string_view(format_str), |
---|
1498 | internal::checked_args<S, Args...>(format_str, args...)); |
---|
1499 | } |
---|
1500 | FMT_END_NAMESPACE |
---|
1501 | |
---|
1502 | #endif // FMT_CORE_H_ |
---|