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 <cstdio> // std::FILE
12 #include <cstring>
13 #include <iterator>
14 #include <string>
15 #include <type_traits>
16
17 // The fmt library version in the form major * 10000 + minor * 100 + patch.
18 #define FMT_VERSION 70103
19
20 #ifdef __clang__
21 # define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
22 #else
23 # define FMT_CLANG_VERSION 0
24 #endif
25
26 #if defined(__GNUC__) && !defined(__clang__)
27 # define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
28 #else
29 # define FMT_GCC_VERSION 0
30 #endif
31
32 #if defined(__INTEL_COMPILER)
33 # define FMT_ICC_VERSION __INTEL_COMPILER
34 #else
35 # define FMT_ICC_VERSION 0
36 #endif
37
38 #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
39 # define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION
40 #else
41 # define FMT_HAS_GXX_CXX11 0
42 #endif
43
44 #ifdef __NVCC__
45 # define FMT_NVCC __NVCC__
46 #else
47 # define FMT_NVCC 0
48 #endif
49
50 #ifdef _MSC_VER
51 # define FMT_MSC_VER _MSC_VER
52 # define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__))
53 #else
54 # define FMT_MSC_VER 0
55 # define FMT_MSC_WARNING(...)
56 #endif
57
58 #ifdef __has_feature
59 # define FMT_HAS_FEATURE(x) __has_feature(x)
60 #else
61 # define FMT_HAS_FEATURE(x) 0
62 #endif
63
64 #if defined(__has_include) && !defined(__INTELLISENSE__) && \
65 (!FMT_ICC_VERSION || FMT_ICC_VERSION >= 1600)
66 # define FMT_HAS_INCLUDE(x) __has_include(x)
67 #else
68 # define FMT_HAS_INCLUDE(x) 0
69 #endif
70
71 #ifdef __has_cpp_attribute
72 # define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
73 #else
74 # define FMT_HAS_CPP_ATTRIBUTE(x) 0
75 #endif
76
77 #define FMT_HAS_CPP14_ATTRIBUTE(attribute) \
78 (__cplusplus >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute))
79
80 #define FMT_HAS_CPP17_ATTRIBUTE(attribute) \
81 (__cplusplus >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute))
82
83 // Check if relaxed C++14 constexpr is supported.
84 // GCC doesn't allow throw in constexpr until version 6 (bug 67371).
85 #ifndef FMT_USE_CONSTEXPR
86 # define FMT_USE_CONSTEXPR \
87 (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \
88 (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \
89 !FMT_NVCC && !FMT_ICC_VERSION
90 #endif
91 #if FMT_USE_CONSTEXPR
92 # define FMT_CONSTEXPR constexpr
93 # define FMT_CONSTEXPR_DECL constexpr
94 #else
95 # define FMT_CONSTEXPR
96 # define FMT_CONSTEXPR_DECL
97 #endif
98
99 #ifndef FMT_OVERRIDE
100 # if FMT_HAS_FEATURE(cxx_override_control) || \
101 (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900
102 # define FMT_OVERRIDE override
103 # else
104 # define FMT_OVERRIDE
105 # endif
106 #endif
107
108 // Check if exceptions are disabled.
109 #ifndef FMT_EXCEPTIONS
110 # if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \
111 FMT_MSC_VER && !_HAS_EXCEPTIONS
112 # define FMT_EXCEPTIONS 0
113 # else
114 # define FMT_EXCEPTIONS 1
115 # endif
116 #endif
117
118 // Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature).
119 #ifndef FMT_USE_NOEXCEPT
120 # define FMT_USE_NOEXCEPT 0
121 #endif
122
123 #if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
124 (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900
125 # define FMT_DETECTED_NOEXCEPT noexcept
126 # define FMT_HAS_CXX11_NOEXCEPT 1
127 #else
128 # define FMT_DETECTED_NOEXCEPT throw()
129 # define FMT_HAS_CXX11_NOEXCEPT 0
130 #endif
131
132 #ifndef FMT_NOEXCEPT
133 # if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT
134 # define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT
135 # else
136 # define FMT_NOEXCEPT
137 # endif
138 #endif
139
140 // [[noreturn]] is disabled on MSVC and NVCC because of bogus unreachable code
141 // warnings.
142 #if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER && \
143 !FMT_NVCC
144 # define FMT_NORETURN [[noreturn]]
145 #else
146 # define FMT_NORETURN
147 #endif
148
149 #ifndef FMT_DEPRECATED
150 # if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900
151 # define FMT_DEPRECATED [[deprecated]]
152 # else
153 # if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__)
154 # define FMT_DEPRECATED __attribute__((deprecated))
155 # elif FMT_MSC_VER
156 # define FMT_DEPRECATED __declspec(deprecated)
157 # else
158 # define FMT_DEPRECATED /* deprecated */
159 # endif
160 # endif
161 #endif
162
163 // Workaround broken [[deprecated]] in the Intel, PGI and NVCC compilers.
164 #if FMT_ICC_VERSION || defined(__PGI) || FMT_NVCC
165 # define FMT_DEPRECATED_ALIAS
166 #else
167 # define FMT_DEPRECATED_ALIAS FMT_DEPRECATED
168 #endif
169
170 #ifndef FMT_INLINE
171 # if FMT_GCC_VERSION || FMT_CLANG_VERSION
172 # define FMT_INLINE inline __attribute__((always_inline))
173 # else
174 # define FMT_INLINE inline
175 # endif
176 #endif
177
178 #ifndef FMT_USE_INLINE_NAMESPACES
179 # if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \
180 (FMT_MSC_VER >= 1900 && (!defined(_MANAGED) || !_MANAGED))
181 # define FMT_USE_INLINE_NAMESPACES 1
182 # else
183 # define FMT_USE_INLINE_NAMESPACES 0
184 # endif
185 #endif
186
187 #ifndef FMT_BEGIN_NAMESPACE
188 # if FMT_USE_INLINE_NAMESPACES
189 # define FMT_INLINE_NAMESPACE inline namespace
190 # define FMT_END_NAMESPACE \
191 } \
192 } \
193 }
194 # else
195 # define FMT_INLINE_NAMESPACE namespace
196 # define FMT_END_NAMESPACE \
197 } \
198 using namespace v7; \
199 } \
200 }
201 # endif
202 # define FMT_BEGIN_NAMESPACE \
203 namespace axom { \
204 namespace fmt { \
205 FMT_INLINE_NAMESPACE v7 {
206 #endif
207
208 #if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
209 # define FMT_CLASS_API FMT_MSC_WARNING(suppress : 4275)
210 # ifdef FMT_EXPORT
211 # define FMT_API __declspec(dllexport)
212 # define FMT_EXTERN_TEMPLATE_API FMT_API
213 # define FMT_EXPORTED
214 # elif defined(FMT_SHARED)
215 # define FMT_API __declspec(dllimport)
216 # define FMT_EXTERN_TEMPLATE_API FMT_API
217 # endif
218 #else
219 # define FMT_CLASS_API
220 #endif
221 #ifndef FMT_API
222 # define FMT_API
223 #endif
224 #ifndef FMT_EXTERN_TEMPLATE_API
225 # define FMT_EXTERN_TEMPLATE_API
226 #endif
227 #ifndef FMT_INSTANTIATION_DEF_API
228 # define FMT_INSTANTIATION_DEF_API FMT_API
229 #endif
230
231 #ifndef FMT_HEADER_ONLY
232 # define FMT_EXTERN extern
233 #else
234 # define FMT_EXTERN
235 #endif
236
237 // libc++ supports string_view in pre-c++17.
238 #if (FMT_HAS_INCLUDE(<string_view>) && \
239 (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \
240 (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
241 # include <string_view>
242 # define FMT_USE_STRING_VIEW
243 #elif FMT_HAS_INCLUDE("experimental/string_view") && __cplusplus >= 201402L
244 # include <experimental/string_view>
245 # define FMT_USE_EXPERIMENTAL_STRING_VIEW
246 #endif
247
248 #ifndef FMT_UNICODE
249 # define FMT_UNICODE !FMT_MSC_VER
250 #endif
251
252 #ifndef FMT_COMPILE_TIME_CHECKS
253 # define FMT_COMPILE_TIME_CHECKS 0
254 #endif
255
256 FMT_BEGIN_NAMESPACE
257
258 // Implementations of enable_if_t and other metafunctions for older systems.
259 template <bool B, class T = void>
260 using enable_if_t = typename std::enable_if<B, T>::type;
261 template <bool B, class T, class F>
262 using conditional_t = typename std::conditional<B, T, F>::type;
263 template <bool B> using bool_constant = std::integral_constant<bool, B>;
264 template <typename T>
265 using remove_reference_t = typename std::remove_reference<T>::type;
266 template <typename T>
267 using remove_const_t = typename std::remove_const<T>::type;
268 template <typename T>
269 using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type;
270 template <typename T> struct type_identity { using type = T; };
271 template <typename T> using type_identity_t = typename type_identity<T>::type;
272
273 struct monostate {};
274
275 // An enable_if helper to be used in template parameters which results in much
276 // shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed
277 // to workaround a bug in MSVC 2019 (see #1140 and #1186).
278 #ifdef FMT_DOC
279 # define FMT_ENABLE_IF(...)
280 #else
281 # define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0
282 #endif
283
284 namespace detail {
285
is_constant_evaluated()286 constexpr bool is_constant_evaluated() FMT_NOEXCEPT {
287 #ifdef __cpp_lib_is_constant_evaluated
288 return std::is_constant_evaluated();
289 #else
290 return false;
291 #endif
292 }
293
294 // A helper function to suppress "conditional expression is constant" warnings.
const_check(T value)295 template <typename T> constexpr T const_check(T value) { return value; }
296
297 FMT_NORETURN FMT_API void assert_fail(const char* file, int line,
298 const char* message);
299
300 #ifndef FMT_ASSERT
301 # ifdef NDEBUG
302 // FMT_ASSERT is not empty to avoid -Werror=empty-body.
303 # define FMT_ASSERT(condition, message) ((void)0)
304 # else
305 # define FMT_ASSERT(condition, message) \
306 ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \
307 ? (void)0 \
308 : ::axom::fmt::detail::assert_fail(__FILE__, __LINE__, (message)))
309 # endif
310 #endif
311
312 #if defined(FMT_USE_STRING_VIEW)
313 template <typename Char> using std_string_view = std::basic_string_view<Char>;
314 #elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
315 template <typename Char>
316 using std_string_view = std::experimental::basic_string_view<Char>;
317 #else
318 template <typename T> struct std_string_view {};
319 #endif
320
321 #ifdef FMT_USE_INT128
322 // Do nothing.
323 #elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \
324 !(FMT_CLANG_VERSION && FMT_MSC_VER)
325 # define FMT_USE_INT128 1
326 using int128_t = __int128_t;
327 using uint128_t = __uint128_t;
328 #else
329 # define FMT_USE_INT128 0
330 #endif
331 #if !FMT_USE_INT128
332 struct int128_t {};
333 struct uint128_t {};
334 #endif
335
336 // Casts a nonnegative integer to unsigned.
337 template <typename Int>
to_unsigned(Int value)338 FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
339 FMT_ASSERT(value >= 0, "negative value");
340 return static_cast<typename std::make_unsigned<Int>::type>(value);
341 }
342
343 FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char micro[] = "\u00B5";
344
is_unicode()345 template <typename Char> constexpr bool is_unicode() {
346 return FMT_UNICODE || sizeof(Char) != 1 ||
347 (sizeof(micro) == 3 && micro[0] == 0xC2 && micro[1] == 0xB5);
348 }
349
350 #ifdef __cpp_char8_t
351 using char8_type = char8_t;
352 #else
353 enum char8_type : unsigned char {};
354 #endif
355 } // namespace detail
356
357 #ifdef FMT_USE_INTERNAL
358 namespace internal = detail; // DEPRECATED
359 #endif
360
361 /**
362 An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
363 subset of the API. ``axom::fmt::basic_string_view`` is used for format strings even
364 if ``std::string_view`` is available to prevent issues when a library is
365 compiled with a different ``-std`` option than the client code (which is not
366 recommended).
367 */
368 template <typename Char> class basic_string_view {
369 private:
370 const Char* data_;
371 size_t size_;
372
373 public:
374 using value_type = Char;
375 using iterator = const Char*;
376
basic_string_view()377 constexpr basic_string_view() FMT_NOEXCEPT : data_(nullptr), size_(0) {}
378
379 /** Constructs a string reference object from a C string and a size. */
basic_string_view(const Char * s,size_t count)380 constexpr basic_string_view(const Char* s, size_t count) FMT_NOEXCEPT
381 : data_(s),
382 size_(count) {}
383
384 /**
385 \rst
386 Constructs a string reference object from a C string computing
387 the size with ``std::char_traits<Char>::length``.
388 \endrst
389 */
390 #if __cplusplus >= 201703L // C++17's char_traits::length() is constexpr.
391 FMT_CONSTEXPR
392 #endif
basic_string_view(const Char * s)393 basic_string_view(const Char* s)
394 : data_(s), size_(std::char_traits<Char>::length(s)) {}
395
396 /** Constructs a string reference from a ``std::basic_string`` object. */
397 template <typename Traits, typename Alloc>
basic_string_view(const std::basic_string<Char,Traits,Alloc> & s)398 FMT_CONSTEXPR basic_string_view(
399 const std::basic_string<Char, Traits, Alloc>& s) FMT_NOEXCEPT
400 : data_(s.data()),
401 size_(s.size()) {}
402
403 template <typename S, FMT_ENABLE_IF(std::is_same<
404 S, detail::std_string_view<Char>>::value)>
basic_string_view(S s)405 FMT_CONSTEXPR basic_string_view(S s) FMT_NOEXCEPT : data_(s.data()),
406 size_(s.size()) {}
407
408 /** Returns a pointer to the string data. */
data()409 constexpr const Char* data() const { return data_; }
410
411 /** Returns the string size. */
size()412 constexpr size_t size() const { return size_; }
413
begin()414 constexpr iterator begin() const { return data_; }
end()415 constexpr iterator end() const { return data_ + size_; }
416
417 constexpr const Char& operator[](size_t pos) const { return data_[pos]; }
418
remove_prefix(size_t n)419 FMT_CONSTEXPR void remove_prefix(size_t n) {
420 data_ += n;
421 size_ -= n;
422 }
423
424 // Lexicographically compare this string reference to other.
compare(basic_string_view other)425 int compare(basic_string_view other) const {
426 size_t str_size = size_ < other.size_ ? size_ : other.size_;
427 int result = std::char_traits<Char>::compare(data_, other.data_, str_size);
428 if (result == 0)
429 result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1);
430 return result;
431 }
432
433 friend bool operator==(basic_string_view lhs, basic_string_view rhs) {
434 return lhs.compare(rhs) == 0;
435 }
436 friend bool operator!=(basic_string_view lhs, basic_string_view rhs) {
437 return lhs.compare(rhs) != 0;
438 }
439 friend bool operator<(basic_string_view lhs, basic_string_view rhs) {
440 return lhs.compare(rhs) < 0;
441 }
442 friend bool operator<=(basic_string_view lhs, basic_string_view rhs) {
443 return lhs.compare(rhs) <= 0;
444 }
445 friend bool operator>(basic_string_view lhs, basic_string_view rhs) {
446 return lhs.compare(rhs) > 0;
447 }
448 friend bool operator>=(basic_string_view lhs, basic_string_view rhs) {
449 return lhs.compare(rhs) >= 0;
450 }
451 };
452
453 using string_view = basic_string_view<char>;
454 using wstring_view = basic_string_view<wchar_t>;
455
456 /** Specifies if ``T`` is a character type. Can be specialized by users. */
457 template <typename T> struct is_char : std::false_type {};
458 template <> struct is_char<char> : std::true_type {};
459 template <> struct is_char<wchar_t> : std::true_type {};
460 template <> struct is_char<detail::char8_type> : std::true_type {};
461 template <> struct is_char<char16_t> : std::true_type {};
462 template <> struct is_char<char32_t> : std::true_type {};
463
464 /**
465 \rst
466 Returns a string view of `s`. In order to add custom string type support to
467 {fmt} provide an overload of `to_string_view` for it in the same namespace as
468 the type for the argument-dependent lookup to work.
469
470 **Example**::
471
472 namespace my_ns {
473 inline string_view to_string_view(const my_string& s) {
474 return {s.data(), s.length()};
475 }
476 }
477 std::string message = axom::fmt::format(my_string("The answer is {}"), 42);
478 \endrst
479 */
480 template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)>
481 inline basic_string_view<Char> to_string_view(const Char* s) {
482 return s;
483 }
484
485 template <typename Char, typename Traits, typename Alloc>
486 inline basic_string_view<Char> to_string_view(
487 const std::basic_string<Char, Traits, Alloc>& s) {
488 return s;
489 }
490
491 template <typename Char>
492 constexpr basic_string_view<Char> to_string_view(basic_string_view<Char> s) {
493 return s;
494 }
495
496 template <typename Char,
497 FMT_ENABLE_IF(!std::is_empty<detail::std_string_view<Char>>::value)>
498 inline basic_string_view<Char> to_string_view(detail::std_string_view<Char> s) {
499 return s;
500 }
501
502 // A base class for compile-time strings. It is defined in the fmt namespace to
503 // make formatting functions visible via ADL, e.g. format(FMT_STRING("{}"), 42).
504 struct compile_string {};
505
506 template <typename S>
507 struct is_compile_string : std::is_base_of<compile_string, S> {};
508
509 template <typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
510 constexpr basic_string_view<typename S::char_type> to_string_view(const S& s) {
511 return s;
512 }
513
514 namespace detail {
515 void to_string_view(...);
516 using axom::fmt::v7::to_string_view;
517
518 // Specifies whether S is a string type convertible to axom::fmt::basic_string_view.
519 // It should be a constexpr function but MSVC 2017 fails to compile it in
520 // enable_if and MSVC 2015 fails to compile it as an alias template.
521 template <typename S>
522 struct is_string : std::is_class<decltype(to_string_view(std::declval<S>()))> {
523 };
524
525 template <typename S, typename = void> struct char_t_impl {};
526 template <typename S> struct char_t_impl<S, enable_if_t<is_string<S>::value>> {
527 using result = decltype(to_string_view(std::declval<S>()));
528 using type = typename result::value_type;
529 };
530
531 // Reports a compile-time error if S is not a valid format string.
532 template <typename..., typename S, FMT_ENABLE_IF(!is_compile_string<S>::value)>
533 FMT_INLINE void check_format_string(const S&) {
534 #ifdef FMT_ENFORCE_COMPILE_STRING
535 static_assert(is_compile_string<S>::value,
536 "FMT_ENFORCE_COMPILE_STRING requires all format strings to use "
537 "FMT_STRING.");
538 #endif
539 }
540 template <typename..., typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
541 void check_format_string(S);
542
543 struct error_handler {
544 constexpr error_handler() = default;
545 constexpr error_handler(const error_handler&) = default;
546
547 // This function is intentionally not constexpr to give a compile-time error.
548 FMT_NORETURN FMT_API void on_error(const char* message);
549 };
550 } // namespace detail
551
552 /** String's character type. */
553 template <typename S> using char_t = typename detail::char_t_impl<S>::type;
554
555 /**
556 \rst
557 Parsing context consisting of a format string range being parsed and an
558 argument counter for automatic indexing.
559
560 You can use one of the following type aliases for common character types:
561
562 +-----------------------+-------------------------------------+
563 | Type | Definition |
564 +=======================+=====================================+
565 | format_parse_context | basic_format_parse_context<char> |
566 +-----------------------+-------------------------------------+
567 | wformat_parse_context | basic_format_parse_context<wchar_t> |
568 +-----------------------+-------------------------------------+
569 \endrst
570 */
571 template <typename Char, typename ErrorHandler = detail::error_handler>
572 class basic_format_parse_context : private ErrorHandler {
573 private:
574 basic_string_view<Char> format_str_;
575 int next_arg_id_;
576
577 public:
578 using char_type = Char;
579 using iterator = typename basic_string_view<Char>::iterator;
580
581 explicit constexpr basic_format_parse_context(
582 basic_string_view<Char> format_str, ErrorHandler eh = {},
583 int next_arg_id = 0)
584 : ErrorHandler(eh), format_str_(format_str), next_arg_id_(next_arg_id) {}
585
586 /**
587 Returns an iterator to the beginning of the format string range being
588 parsed.
589 */
590 constexpr iterator begin() const FMT_NOEXCEPT { return format_str_.begin(); }
591
592 /**
593 Returns an iterator past the end of the format string range being parsed.
594 */
595 constexpr iterator end() const FMT_NOEXCEPT { return format_str_.end(); }
596
597 /** Advances the begin iterator to ``it``. */
598 FMT_CONSTEXPR void advance_to(iterator it) {
599 format_str_.remove_prefix(detail::to_unsigned(it - begin()));
600 }
601
602 /**
603 Reports an error if using the manual argument indexing; otherwise returns
604 the next argument index and switches to the automatic indexing.
605 */
606 FMT_CONSTEXPR int next_arg_id() {
607 // Don't check if the argument id is valid to avoid overhead and because it
608 // will be checked during formatting anyway.
609 if (next_arg_id_ >= 0) return next_arg_id_++;
610 on_error("cannot switch from manual to automatic argument indexing");
611 return 0;
612 }
613
614 /**
615 Reports an error if using the automatic argument indexing; otherwise
616 switches to the manual indexing.
617 */
618 FMT_CONSTEXPR void check_arg_id(int) {
619 if (next_arg_id_ > 0)
620 on_error("cannot switch from automatic to manual argument indexing");
621 else
622 next_arg_id_ = -1;
623 }
624
625 FMT_CONSTEXPR void check_arg_id(basic_string_view<Char>) {}
626
627 FMT_CONSTEXPR void on_error(const char* message) {
628 ErrorHandler::on_error(message);
629 }
630
631 constexpr ErrorHandler error_handler() const { return *this; }
632 };
633
634 using format_parse_context = basic_format_parse_context<char>;
635 using wformat_parse_context = basic_format_parse_context<wchar_t>;
636
637 template <typename Context> class basic_format_arg;
638 template <typename Context> class basic_format_args;
639 template <typename Context> class dynamic_format_arg_store;
640
641 // A formatter for objects of type T.
642 template <typename T, typename Char = char, typename Enable = void>
643 struct formatter {
644 // A deleted default constructor indicates a disabled formatter.
645 formatter() = delete;
646 };
647
648 // Specifies if T has an enabled formatter specialization. A type can be
649 // formattable even if it doesn't have a formatter e.g. via a conversion.
650 template <typename T, typename Context>
651 using has_formatter =
652 std::is_constructible<typename Context::template formatter_type<T>>;
653
654 // Checks whether T is a container with contiguous storage.
655 template <typename T> struct is_contiguous : std::false_type {};
656 template <typename Char>
657 struct is_contiguous<std::basic_string<Char>> : std::true_type {};
658
659 namespace detail {
660
661 // Extracts a reference to the container from back_insert_iterator.
662 template <typename Container>
663 inline Container& get_container(std::back_insert_iterator<Container> it) {
664 using bi_iterator = std::back_insert_iterator<Container>;
665 struct accessor : bi_iterator {
666 accessor(bi_iterator iter) : bi_iterator(iter) {}
667 using bi_iterator::container;
668 };
669 return *accessor(it).container;
670 }
671
672 /**
673 \rst
674 A contiguous memory buffer with an optional growing ability. It is an internal
675 class and shouldn't be used directly, only via `~axom::fmt::basic_memory_buffer`.
676 \endrst
677 */
678 template <typename T> class buffer {
679 private:
680 T* ptr_;
681 size_t size_;
682 size_t capacity_;
683
684 protected:
685 // Don't initialize ptr_ since it is not accessed to save a few cycles.
686 FMT_MSC_WARNING(suppress : 26495)
687 buffer(size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {}
688
689 buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) FMT_NOEXCEPT
690 : ptr_(p),
691 size_(sz),
692 capacity_(cap) {}
693
694 ~buffer() = default;
695
696 /** Sets the buffer data and capacity. */
697 void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT {
698 ptr_ = buf_data;
699 capacity_ = buf_capacity;
700 }
701
702 /** Increases the buffer capacity to hold at least *capacity* elements. */
703 virtual void grow(size_t capacity) = 0;
704
705 public:
706 using value_type = T;
707 using const_reference = const T&;
708
709 buffer(const buffer&) = delete;
710 void operator=(const buffer&) = delete;
711
712 T* begin() FMT_NOEXCEPT { return ptr_; }
713 T* end() FMT_NOEXCEPT { return ptr_ + size_; }
714
715 const T* begin() const FMT_NOEXCEPT { return ptr_; }
716 const T* end() const FMT_NOEXCEPT { return ptr_ + size_; }
717
718 /** Returns the size of this buffer. */
719 size_t size() const FMT_NOEXCEPT { return size_; }
720
721 /** Returns the capacity of this buffer. */
722 size_t capacity() const FMT_NOEXCEPT { return capacity_; }
723
724 /** Returns a pointer to the buffer data. */
725 T* data() FMT_NOEXCEPT { return ptr_; }
726
727 /** Returns a pointer to the buffer data. */
728 const T* data() const FMT_NOEXCEPT { return ptr_; }
729
730 /** Clears this buffer. */
731 void clear() { size_ = 0; }
732
733 // Tries resizing the buffer to contain *count* elements. If T is a POD type
734 // the new elements may not be initialized.
735 void try_resize(size_t count) {
736 try_reserve(count);
737 size_ = count <= capacity_ ? count : capacity_;
738 }
739
740 // Tries increasing the buffer capacity to *new_capacity*. It can increase the
741 // capacity by a smaller amount than requested but guarantees there is space
742 // for at least one additional element either by increasing the capacity or by
743 // flushing the buffer if it is full.
744 void try_reserve(size_t new_capacity) {
745 if (new_capacity > capacity_) grow(new_capacity);
746 }
747
748 void push_back(const T& value) {
749 try_reserve(size_ + 1);
750 ptr_[size_++] = value;
751 }
752
753 /** Appends data to the end of the buffer. */
754 template <typename U> void append(const U* begin, const U* end);
755
756 template <typename I> T& operator[](I index) { return ptr_[index]; }
757 template <typename I> const T& operator[](I index) const {
758 return ptr_[index];
759 }
760 };
761
762 struct buffer_traits {
763 explicit buffer_traits(size_t) {}
764 size_t count() const { return 0; }
765 size_t limit(size_t size) { return size; }
766 };
767
768 class fixed_buffer_traits {
769 private:
770 size_t count_ = 0;
771 size_t limit_;
772
773 public:
774 explicit fixed_buffer_traits(size_t limit) : limit_(limit) {}
775 size_t count() const { return count_; }
776 size_t limit(size_t size) {
777 size_t n = limit_ > count_ ? limit_ - count_ : 0;
778 count_ += size;
779 return size < n ? size : n;
780 }
781 };
782
783 // A buffer that writes to an output iterator when flushed.
784 template <typename OutputIt, typename T, typename Traits = buffer_traits>
785 class iterator_buffer final : public Traits, public buffer<T> {
786 private:
787 OutputIt out_;
788 enum { buffer_size = 256 };
789 T data_[buffer_size];
790
791 protected:
792 void grow(size_t) final FMT_OVERRIDE {
793 if (this->size() == buffer_size) flush();
794 }
795 void flush();
796
797 public:
798 explicit iterator_buffer(OutputIt out, size_t n = buffer_size)
799 : Traits(n), buffer<T>(data_, 0, buffer_size), out_(out) {}
800 ~iterator_buffer() { flush(); }
801
802 OutputIt out() {
803 flush();
804 return out_;
805 }
806 size_t count() const { return Traits::count() + this->size(); }
807 };
808
809 template <typename T> class iterator_buffer<T*, T> final : public buffer<T> {
810 protected:
811 void grow(size_t) final FMT_OVERRIDE {}
812
813 public:
814 explicit iterator_buffer(T* out, size_t = 0) : buffer<T>(out, 0, ~size_t()) {}
815
816 T* out() { return &*this->end(); }
817 };
818
819 // A buffer that writes to a container with the contiguous storage.
820 template <typename Container>
821 class iterator_buffer<std::back_insert_iterator<Container>,
822 enable_if_t<is_contiguous<Container>::value,
823 typename Container::value_type>>
824 final : public buffer<typename Container::value_type> {
825 private:
826 Container& container_;
827
828 protected:
829 void grow(size_t capacity) final FMT_OVERRIDE {
830 container_.resize(capacity);
831 this->set(&container_[0], capacity);
832 }
833
834 public:
835 explicit iterator_buffer(Container& c)
836 : buffer<typename Container::value_type>(c.size()), container_(c) {}
837 explicit iterator_buffer(std::back_insert_iterator<Container> out, size_t = 0)
838 : iterator_buffer(get_container(out)) {}
839 std::back_insert_iterator<Container> out() {
840 return std::back_inserter(container_);
841 }
842 };
843
844 // A buffer that counts the number of code units written discarding the output.
845 template <typename T = char> class counting_buffer final : public buffer<T> {
846 private:
847 enum { buffer_size = 256 };
848 T data_[buffer_size];
849 size_t count_ = 0;
850
851 protected:
852 void grow(size_t) final FMT_OVERRIDE {
853 if (this->size() != buffer_size) return;
854 count_ += this->size();
855 this->clear();
856 }
857
858 public:
859 counting_buffer() : buffer<T>(data_, 0, buffer_size) {}
860
861 size_t count() { return count_ + this->size(); }
862 };
863
864 // An output iterator that appends to the buffer.
865 // It is used to reduce symbol sizes for the common case.
866 template <typename T>
867 class buffer_appender : public std::back_insert_iterator<buffer<T>> {
868 using base = std::back_insert_iterator<buffer<T>>;
869
870 public:
871 explicit buffer_appender(buffer<T>& buf) : base(buf) {}
872 buffer_appender(base it) : base(it) {}
873
874 buffer_appender& operator++() {
875 base::operator++();
876 return *this;
877 }
878
879 buffer_appender operator++(int) {
880 buffer_appender tmp = *this;
881 ++*this;
882 return tmp;
883 }
884 };
885
886 // Maps an output iterator into a buffer.
887 template <typename T, typename OutputIt>
888 iterator_buffer<OutputIt, T> get_buffer(OutputIt);
889 template <typename T> buffer<T>& get_buffer(buffer_appender<T>);
890
891 template <typename OutputIt> OutputIt get_buffer_init(OutputIt out) {
892 return out;
893 }
894 template <typename T> buffer<T>& get_buffer_init(buffer_appender<T> out) {
895 return get_container(out);
896 }
897
898 template <typename Buffer>
899 auto get_iterator(Buffer& buf) -> decltype(buf.out()) {
900 return buf.out();
901 }
902 template <typename T> buffer_appender<T> get_iterator(buffer<T>& buf) {
903 return buffer_appender<T>(buf);
904 }
905
906 template <typename T, typename Char = char, typename Enable = void>
907 struct fallback_formatter {
908 fallback_formatter() = delete;
909 };
910
911 // Specifies if T has an enabled fallback_formatter specialization.
912 template <typename T, typename Context>
913 using has_fallback_formatter =
914 std::is_constructible<fallback_formatter<T, typename Context::char_type>>;
915
916 struct view {};
917
918 template <typename Char, typename T> struct named_arg : view {
919 const Char* name;
920 const T& value;
921 named_arg(const Char* n, const T& v) : name(n), value(v) {}
922 };
923
924 template <typename Char> struct named_arg_info {
925 const Char* name;
926 int id;
927 };
928
929 template <typename T, typename Char, size_t NUM_ARGS, size_t NUM_NAMED_ARGS>
930 struct arg_data {
931 // args_[0].named_args points to named_args_ to avoid bloating format_args.
932 // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
933 T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : +1)];
934 named_arg_info<Char> named_args_[NUM_NAMED_ARGS];
935
936 template <typename... U>
937 arg_data(const U&... init) : args_{T(named_args_, NUM_NAMED_ARGS), init...} {}
938 arg_data(const arg_data& other) = delete;
939 const T* args() const { return args_ + 1; }
940 named_arg_info<Char>* named_args() { return named_args_; }
941 };
942
943 template <typename T, typename Char, size_t NUM_ARGS>
944 struct arg_data<T, Char, NUM_ARGS, 0> {
945 // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
946 T args_[NUM_ARGS != 0 ? NUM_ARGS : +1];
947
948 template <typename... U>
949 FMT_CONSTEXPR FMT_INLINE arg_data(const U&... init) : args_{init...} {}
950 FMT_CONSTEXPR FMT_INLINE const T* args() const { return args_; }
951 FMT_CONSTEXPR FMT_INLINE std::nullptr_t named_args() { return nullptr; }
952 };
953
954 template <typename Char>
955 inline void init_named_args(named_arg_info<Char>*, int, int) {}
956
957 template <typename Char, typename T, typename... Tail>
958 void init_named_args(named_arg_info<Char>* named_args, int arg_count,
959 int named_arg_count, const T&, const Tail&... args) {
960 init_named_args(named_args, arg_count + 1, named_arg_count, args...);
961 }
962
963 template <typename Char, typename T, typename... Tail>
964 void init_named_args(named_arg_info<Char>* named_args, int arg_count,
965 int named_arg_count, const named_arg<Char, T>& arg,
966 const Tail&... args) {
967 named_args[named_arg_count++] = {arg.name, arg_count};
968 init_named_args(named_args, arg_count + 1, named_arg_count, args...);
969 }
970
971 template <typename... Args>
972 FMT_CONSTEXPR FMT_INLINE void init_named_args(std::nullptr_t, int, int,
973 const Args&...) {}
974
975 template <typename T> struct is_named_arg : std::false_type {};
976
977 template <typename T, typename Char>
978 struct is_named_arg<named_arg<Char, T>> : std::true_type {};
979
980 template <bool B = false> constexpr size_t count() { return B ? 1 : 0; }
981 template <bool B1, bool B2, bool... Tail> constexpr size_t count() {
982 return (B1 ? 1 : 0) + count<B2, Tail...>();
983 }
984
985 template <typename... Args> constexpr size_t count_named_args() {
986 return count<is_named_arg<Args>::value...>();
987 }
988
989 enum class type {
990 none_type,
991 // Integer types should go first,
992 int_type,
993 uint_type,
994 long_long_type,
995 ulong_long_type,
996 int128_type,
997 uint128_type,
998 bool_type,
999 char_type,
1000 last_integer_type = char_type,
1001 // followed by floating-point types.
1002 float_type,
1003 double_type,
1004 long_double_type,
1005 last_numeric_type = long_double_type,
1006 cstring_type,
1007 string_type,
1008 pointer_type,
1009 custom_type
1010 };
1011
1012 // Maps core type T to the corresponding type enum constant.
1013 template <typename T, typename Char>
1014 struct type_constant : std::integral_constant<type, type::custom_type> {};
1015
1016 #define FMT_TYPE_CONSTANT(Type, constant) \
1017 template <typename Char> \
1018 struct type_constant<Type, Char> \
1019 : std::integral_constant<type, type::constant> {}
1020
1021 FMT_TYPE_CONSTANT(int, int_type);
1022 FMT_TYPE_CONSTANT(unsigned, uint_type);
1023 FMT_TYPE_CONSTANT(long long, long_long_type);
1024 FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type);
1025 FMT_TYPE_CONSTANT(int128_t, int128_type);
1026 FMT_TYPE_CONSTANT(uint128_t, uint128_type);
1027 FMT_TYPE_CONSTANT(bool, bool_type);
1028 FMT_TYPE_CONSTANT(Char, char_type);
1029 FMT_TYPE_CONSTANT(float, float_type);
1030 FMT_TYPE_CONSTANT(double, double_type);
1031 FMT_TYPE_CONSTANT(long double, long_double_type);
1032 FMT_TYPE_CONSTANT(const Char*, cstring_type);
1033 FMT_TYPE_CONSTANT(basic_string_view<Char>, string_type);
1034 FMT_TYPE_CONSTANT(const void*, pointer_type);
1035
1036 constexpr bool is_integral_type(type t) {
1037 return t > type::none_type && t <= type::last_integer_type;
1038 }
1039
1040 constexpr bool is_arithmetic_type(type t) {
1041 return t > type::none_type && t <= type::last_numeric_type;
1042 }
1043
1044 template <typename Char> struct string_value {
1045 const Char* data;
1046 size_t size;
1047 };
1048
1049 template <typename Char> struct named_arg_value {
1050 const named_arg_info<Char>* data;
1051 size_t size;
1052 };
1053
1054 template <typename Context> struct custom_value {
1055 using parse_context = typename Context::parse_context_type;
1056 const void* value;
1057 void (*format)(const void* arg, parse_context& parse_ctx, Context& ctx);
1058 };
1059
1060 // A formatting argument value.
1061 template <typename Context> class value {
1062 public:
1063 using char_type = typename Context::char_type;
1064
1065 union {
1066 int int_value;
1067 unsigned uint_value;
1068 long long long_long_value;
1069 unsigned long long ulong_long_value;
1070 int128_t int128_value;
1071 uint128_t uint128_value;
1072 bool bool_value;
1073 char_type char_value;
1074 float float_value;
1075 double double_value;
1076 long double long_double_value;
1077 const void* pointer;
1078 string_value<char_type> string;
1079 custom_value<Context> custom;
1080 named_arg_value<char_type> named_args;
1081 };
1082
1083 constexpr FMT_INLINE value(int val = 0) : int_value(val) {}
1084 constexpr FMT_INLINE value(unsigned val) : uint_value(val) {}
1085 constexpr FMT_INLINE value(long long val) : long_long_value(val) {}
1086 constexpr FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {}
1087 FMT_INLINE value(int128_t val) : int128_value(val) {}
1088 FMT_INLINE value(uint128_t val) : uint128_value(val) {}
1089 FMT_INLINE value(float val) : float_value(val) {}
1090 FMT_INLINE value(double val) : double_value(val) {}
1091 FMT_INLINE value(long double val) : long_double_value(val) {}
1092 constexpr FMT_INLINE value(bool val) : bool_value(val) {}
1093 constexpr FMT_INLINE value(char_type val) : char_value(val) {}
1094 FMT_CONSTEXPR FMT_INLINE value(const char_type* val) {
1095 string.data = val;
1096 if (is_constant_evaluated()) string.size = {};
1097 }
1098 FMT_CONSTEXPR FMT_INLINE value(basic_string_view<char_type> val) {
1099 string.data = val.data();
1100 string.size = val.size();
1101 }
1102 FMT_INLINE value(const void* val) : pointer(val) {}
1103 FMT_INLINE value(const named_arg_info<char_type>* args, size_t size)
1104 : named_args{args, size} {}
1105
1106 template <typename T> FMT_INLINE value(const T& val) {
1107 custom.value = &val;
1108 // Get the formatter type through the context to allow different contexts
1109 // have different extension points, e.g. `formatter<T>` for `format` and
1110 // `printf_formatter<T>` for `printf`.
1111 custom.format = format_custom_arg<
1112 T, conditional_t<has_formatter<T, Context>::value,
1113 typename Context::template formatter_type<T>,
1114 fallback_formatter<T, char_type>>>;
1115 }
1116
1117 private:
1118 // Formats an argument of a custom type, such as a user-defined class.
1119 template <typename T, typename Formatter>
1120 static void format_custom_arg(const void* arg,
1121 typename Context::parse_context_type& parse_ctx,
1122 Context& ctx) {
1123 Formatter f;
1124 parse_ctx.advance_to(f.parse(parse_ctx));
1125 ctx.advance_to(f.format(*static_cast<const T*>(arg), ctx));
1126 }
1127 };
1128
1129 template <typename Context, typename T>
1130 FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T& value);
1131
1132 // To minimize the number of types we need to deal with, long is translated
1133 // either to int or to long long depending on its size.
1134 enum { long_short = sizeof(long) == sizeof(int) };
1135 using long_type = conditional_t<long_short, int, long long>;
1136 using ulong_type = conditional_t<long_short, unsigned, unsigned long long>;
1137
1138 struct unformattable {};
1139
1140 // Maps formatting arguments to core types.
1141 template <typename Context> struct arg_mapper {
1142 using char_type = typename Context::char_type;
1143
1144 FMT_CONSTEXPR int map(signed char val) { return val; }
1145 FMT_CONSTEXPR unsigned map(unsigned char val) { return val; }
1146 FMT_CONSTEXPR int map(short val) { return val; }
1147 FMT_CONSTEXPR unsigned map(unsigned short val) { return val; }
1148 FMT_CONSTEXPR int map(int val) { return val; }
1149 FMT_CONSTEXPR unsigned map(unsigned val) { return val; }
1150 FMT_CONSTEXPR long_type map(long val) { return val; }
1151 FMT_CONSTEXPR ulong_type map(unsigned long val) { return val; }
1152 FMT_CONSTEXPR long long map(long long val) { return val; }
1153 FMT_CONSTEXPR unsigned long long map(unsigned long long val) { return val; }
1154 FMT_CONSTEXPR int128_t map(int128_t val) { return val; }
1155 FMT_CONSTEXPR uint128_t map(uint128_t val) { return val; }
1156 FMT_CONSTEXPR bool map(bool val) { return val; }
1157
1158 template <typename T, FMT_ENABLE_IF(is_char<T>::value)>
1159 FMT_CONSTEXPR char_type map(T val) {
1160 static_assert(
1161 std::is_same<T, char>::value || std::is_same<T, char_type>::value,
1162 "mixing character types is disallowed");
1163 return val;
1164 }
1165
1166 FMT_CONSTEXPR float map(float val) { return val; }
1167 FMT_CONSTEXPR double map(double val) { return val; }
1168 FMT_CONSTEXPR long double map(long double val) { return val; }
1169
1170 FMT_CONSTEXPR const char_type* map(char_type* val) { return val; }
1171 FMT_CONSTEXPR const char_type* map(const char_type* val) { return val; }
1172 template <typename T, FMT_ENABLE_IF(is_string<T>::value)>
1173 FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
1174 static_assert(std::is_same<char_type, char_t<T>>::value,
1175 "mixing character types is disallowed");
1176 return to_string_view(val);
1177 }
1178 template <typename T,
1179 FMT_ENABLE_IF(
1180 std::is_constructible<basic_string_view<char_type>, T>::value &&
1181 !is_string<T>::value && !has_formatter<T, Context>::value &&
1182 !has_fallback_formatter<T, Context>::value)>
1183 FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
1184 return basic_string_view<char_type>(val);
1185 }
1186 template <
1187 typename T,
1188 FMT_ENABLE_IF(
1189 std::is_constructible<std_string_view<char_type>, T>::value &&
1190 !std::is_constructible<basic_string_view<char_type>, T>::value &&
1191 !is_string<T>::value && !has_formatter<T, Context>::value &&
1192 !has_fallback_formatter<T, Context>::value)>
1193 FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
1194 return std_string_view<char_type>(val);
1195 }
1196 FMT_CONSTEXPR const char* map(const signed char* val) {
1197 static_assert(std::is_same<char_type, char>::value, "invalid string type");
1198 return reinterpret_cast<const char*>(val);
1199 }
1200 FMT_CONSTEXPR const char* map(const unsigned char* val) {
1201 static_assert(std::is_same<char_type, char>::value, "invalid string type");
1202 return reinterpret_cast<const char*>(val);
1203 }
1204 FMT_CONSTEXPR const char* map(signed char* val) {
1205 const auto* const_val = val;
1206 return map(const_val);
1207 }
1208 FMT_CONSTEXPR const char* map(unsigned char* val) {
1209 const auto* const_val = val;
1210 return map(const_val);
1211 }
1212
1213 FMT_CONSTEXPR const void* map(void* val) { return val; }
1214 FMT_CONSTEXPR const void* map(const void* val) { return val; }
1215 FMT_CONSTEXPR const void* map(std::nullptr_t val) { return val; }
1216
1217 // We use SFINAE instead of a const T* parameter to avoid conflicting with
1218 // the C array overload.
1219 template <typename T>
1220 FMT_CONSTEXPR auto map(T) -> enable_if_t<std::is_pointer<T>::value, int> {
1221 // Formatting of arbitrary pointers is disallowed. If you want to output
1222 // a pointer cast it to "void *" or "const void *". In particular, this
1223 // forbids formatting of "[const] volatile char *" which is printed as bool
1224 // by iostreams.
1225 static_assert(!sizeof(T), "formatting of non-void pointers is disallowed");
1226 return 0;
1227 }
1228
1229 template <typename T, std::size_t N>
1230 FMT_CONSTEXPR auto map(const T (&values)[N]) -> const T (&)[N] {
1231 return values;
1232 }
1233
1234 template <typename T,
1235 FMT_ENABLE_IF(std::is_enum<T>::value &&
1236 !has_formatter<T, Context>::value &&
1237 !has_fallback_formatter<T, Context>::value)>
1238 FMT_CONSTEXPR auto map(const T& val)
1239 -> decltype(std::declval<arg_mapper>().map(
1240 static_cast<typename std::underlying_type<T>::type>(val))) {
1241 return map(static_cast<typename std::underlying_type<T>::type>(val));
1242 }
1243 template <typename T,
1244 FMT_ENABLE_IF(!is_string<T>::value && !is_char<T>::value &&
1245 (has_formatter<T, Context>::value ||
1246 has_fallback_formatter<T, Context>::value))>
1247 FMT_CONSTEXPR const T& map(const T& val) {
1248 return val;
1249 }
1250
1251 template <typename T>
1252 FMT_CONSTEXPR auto map(const named_arg<char_type, T>& val)
1253 -> decltype(std::declval<arg_mapper>().map(val.value)) {
1254 return map(val.value);
1255 }
1256
1257 unformattable map(...) { return {}; }
1258 };
1259
1260 // A type constant after applying arg_mapper<Context>.
1261 template <typename T, typename Context>
1262 using mapped_type_constant =
1263 type_constant<decltype(arg_mapper<Context>().map(std::declval<const T&>())),
1264 typename Context::char_type>;
1265
1266 enum { packed_arg_bits = 4 };
1267 // Maximum number of arguments with packed types.
1268 enum { max_packed_args = 62 / packed_arg_bits };
1269 enum : unsigned long long { is_unpacked_bit = 1ULL << 63 };
1270 enum : unsigned long long { has_named_args_bit = 1ULL << 62 };
1271 } // namespace detail
1272
1273 // A formatting argument. It is a trivially copyable/constructible type to
1274 // allow storage in basic_memory_buffer.
1275 template <typename Context> class basic_format_arg {
1276 private:
1277 detail::value<Context> value_;
1278 detail::type type_;
1279
1280 template <typename ContextType, typename T>
1281 friend FMT_CONSTEXPR basic_format_arg<ContextType> detail::make_arg(
1282 const T& value);
1283
1284 template <typename Visitor, typename Ctx>
1285 friend FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis,
1286 const basic_format_arg<Ctx>& arg)
1287 -> decltype(vis(0));
1288
1289 friend class basic_format_args<Context>;
1290 friend class dynamic_format_arg_store<Context>;
1291
1292 using char_type = typename Context::char_type;
1293
1294 template <typename T, typename Char, size_t NUM_ARGS, size_t NUM_NAMED_ARGS>
1295 friend struct detail::arg_data;
1296
1297 basic_format_arg(const detail::named_arg_info<char_type>* args, size_t size)
1298 : value_(args, size) {}
1299
1300 public:
1301 class handle {
1302 public:
1303 explicit handle(detail::custom_value<Context> custom) : custom_(custom) {}
1304
1305 void format(typename Context::parse_context_type& parse_ctx,
1306 Context& ctx) const {
1307 custom_.format(custom_.value, parse_ctx, ctx);
1308 }
1309
1310 private:
1311 detail::custom_value<Context> custom_;
1312 };
1313
1314 constexpr basic_format_arg() : type_(detail::type::none_type) {}
1315
1316 constexpr explicit operator bool() const FMT_NOEXCEPT {
1317 return type_ != detail::type::none_type;
1318 }
1319
1320 detail::type type() const { return type_; }
1321
1322 bool is_integral() const { return detail::is_integral_type(type_); }
1323 bool is_arithmetic() const { return detail::is_arithmetic_type(type_); }
1324 };
1325
1326 /**
1327 \rst
1328 Visits an argument dispatching to the appropriate visit method based on
1329 the argument type. For example, if the argument type is ``double`` then
1330 ``vis(value)`` will be called with the value of type ``double``.
1331 \endrst
1332 */
1333 template <typename Visitor, typename Context>
1334 FMT_CONSTEXPR_DECL FMT_INLINE auto visit_format_arg(
1335 Visitor&& vis, const basic_format_arg<Context>& arg) -> decltype(vis(0)) {
1336 using char_type = typename Context::char_type;
1337 switch (arg.type_) {
1338 case detail::type::none_type:
1339 break;
1340 case detail::type::int_type:
1341 return vis(arg.value_.int_value);
1342 case detail::type::uint_type:
1343 return vis(arg.value_.uint_value);
1344 case detail::type::long_long_type:
1345 return vis(arg.value_.long_long_value);
1346 case detail::type::ulong_long_type:
1347 return vis(arg.value_.ulong_long_value);
1348 #if FMT_USE_INT128
1349 case detail::type::int128_type:
1350 return vis(arg.value_.int128_value);
1351 case detail::type::uint128_type:
1352 return vis(arg.value_.uint128_value);
1353 #else
1354 case detail::type::int128_type:
1355 case detail::type::uint128_type:
1356 break;
1357 #endif
1358 case detail::type::bool_type:
1359 return vis(arg.value_.bool_value);
1360 case detail::type::char_type:
1361 return vis(arg.value_.char_value);
1362 case detail::type::float_type:
1363 return vis(arg.value_.float_value);
1364 case detail::type::double_type:
1365 return vis(arg.value_.double_value);
1366 case detail::type::long_double_type:
1367 return vis(arg.value_.long_double_value);
1368 case detail::type::cstring_type:
1369 return vis(arg.value_.string.data);
1370 case detail::type::string_type:
1371 return vis(basic_string_view<char_type>(arg.value_.string.data,
1372 arg.value_.string.size));
1373 case detail::type::pointer_type:
1374 return vis(arg.value_.pointer);
1375 case detail::type::custom_type:
1376 return vis(typename basic_format_arg<Context>::handle(arg.value_.custom));
1377 }
1378 return vis(monostate());
1379 }
1380
1381 template <typename T> struct formattable : std::false_type {};
1382
1383 namespace detail {
1384
1385 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 500
1386 // A workaround for gcc 4.8 to make void_t work in a SFINAE context.
1387 template <typename... Ts> struct void_t_impl { using type = void; };
1388 template <typename... Ts>
1389 using void_t = typename detail::void_t_impl<Ts...>::type;
1390 #else
1391 template <typename...> using void_t = void;
1392 #endif
1393
1394 template <typename It, typename T, typename Enable = void>
1395 struct is_output_iterator : std::false_type {};
1396
1397 template <typename It, typename T>
1398 struct is_output_iterator<
1399 It, T,
1400 void_t<typename std::iterator_traits<It>::iterator_category,
1401 decltype(*std::declval<It>() = std::declval<T>())>>
1402 : std::true_type {};
1403
1404 template <typename OutputIt>
1405 struct is_back_insert_iterator : std::false_type {};
1406 template <typename Container>
1407 struct is_back_insert_iterator<std::back_insert_iterator<Container>>
1408 : std::true_type {};
1409
1410 template <typename OutputIt>
1411 struct is_contiguous_back_insert_iterator : std::false_type {};
1412 template <typename Container>
1413 struct is_contiguous_back_insert_iterator<std::back_insert_iterator<Container>>
1414 : is_contiguous<Container> {};
1415 template <typename Char>
1416 struct is_contiguous_back_insert_iterator<buffer_appender<Char>>
1417 : std::true_type {};
1418
1419 // A type-erased reference to an std::locale to avoid heavy <locale> include.
1420 class locale_ref {
1421 private:
1422 const void* locale_; // A type-erased pointer to std::locale.
1423
1424 public:
1425 constexpr locale_ref() : locale_(nullptr) {}
1426 template <typename Locale> explicit locale_ref(const Locale& loc);
1427
1428 explicit operator bool() const FMT_NOEXCEPT { return locale_ != nullptr; }
1429
1430 template <typename Locale> Locale get() const;
1431 };
1432
1433 template <typename> constexpr unsigned long long encode_types() { return 0; }
1434
1435 template <typename Context, typename Arg, typename... Args>
1436 constexpr unsigned long long encode_types() {
1437 return static_cast<unsigned>(mapped_type_constant<Arg, Context>::value) |
1438 (encode_types<Context, Args...>() << packed_arg_bits);
1439 }
1440
1441 template <typename Context, typename T>
1442 FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T& value) {
1443 basic_format_arg<Context> arg;
1444 arg.type_ = mapped_type_constant<T, Context>::value;
1445 arg.value_ = arg_mapper<Context>().map(value);
1446 return arg;
1447 }
1448
1449 template <typename T> int check(unformattable) {
1450 static_assert(
1451 formattable<T>(),
1452 "Cannot format an argument. To make type T formattable provide a "
1453 "formatter<T> specialization: https://fmt.dev/latest/api.html#udt");
1454 return 0;
1455 }
1456 template <typename T, typename U> constexpr const U& check(const U& val) {
1457 return val;
1458 }
1459
1460 // The type template parameter is there to avoid an ODR violation when using
1461 // a fallback formatter in one translation unit and an implicit conversion in
1462 // another (not recommended).
1463 template <bool IS_PACKED, typename Context, type, typename T,
1464 FMT_ENABLE_IF(IS_PACKED)>
1465 constexpr value<Context> make_arg(const T& val) {
1466 return detail::check<T>(arg_mapper<Context>().map(val));
1467 }
1468
1469 template <bool IS_PACKED, typename Context, type, typename T,
1470 FMT_ENABLE_IF(!IS_PACKED)>
1471 inline basic_format_arg<Context> make_arg(const T& value) {
1472 return make_arg<Context>(value);
1473 }
1474 } // namespace detail
1475
1476 // Formatting context.
1477 template <typename OutputIt, typename Char> class basic_format_context {
1478 public:
1479 /** The character type for the output. */
1480 using char_type = Char;
1481
1482 private:
1483 OutputIt out_;
1484 basic_format_args<basic_format_context> args_;
1485 detail::locale_ref loc_;
1486
1487 public:
1488 using iterator = OutputIt;
1489 using format_arg = basic_format_arg<basic_format_context>;
1490 using parse_context_type = basic_format_parse_context<Char>;
1491 template <typename T> using formatter_type = formatter<T, char_type>;
1492
1493 basic_format_context(const basic_format_context&) = delete;
1494 void operator=(const basic_format_context&) = delete;
1495 /**
1496 Constructs a ``basic_format_context`` object. References to the arguments are
1497 stored in the object so make sure they have appropriate lifetimes.
1498 */
1499 constexpr basic_format_context(
1500 OutputIt out, basic_format_args<basic_format_context> ctx_args,
1501 detail::locale_ref loc = detail::locale_ref())
1502 : out_(out), args_(ctx_args), loc_(loc) {}
1503
1504 constexpr format_arg arg(int id) const { return args_.get(id); }
1505 FMT_CONSTEXPR format_arg arg(basic_string_view<char_type> name) {
1506 return args_.get(name);
1507 }
1508 int arg_id(basic_string_view<char_type> name) { return args_.get_id(name); }
1509 const basic_format_args<basic_format_context>& args() const { return args_; }
1510
1511 FMT_CONSTEXPR detail::error_handler error_handler() { return {}; }
1512 void on_error(const char* message) { error_handler().on_error(message); }
1513
1514 // Returns an iterator to the beginning of the output range.
1515 FMT_CONSTEXPR iterator out() { return out_; }
1516
1517 // Advances the begin iterator to ``it``.
1518 void advance_to(iterator it) {
1519 if (!detail::is_back_insert_iterator<iterator>()) out_ = it;
1520 }
1521
1522 FMT_CONSTEXPR detail::locale_ref locale() { return loc_; }
1523 };
1524
1525 template <typename Char>
1526 using buffer_context =
1527 basic_format_context<detail::buffer_appender<Char>, Char>;
1528 using format_context = buffer_context<char>;
1529 using wformat_context = buffer_context<wchar_t>;
1530
1531 // Workaround an alias issue: https://stackoverflow.com/q/62767544/471164.
1532 #define FMT_BUFFER_CONTEXT(Char) \
1533 basic_format_context<detail::buffer_appender<Char>, Char>
1534
1535 template <typename T, typename Char = char>
1536 using is_formattable = bool_constant<!std::is_same<
1537 decltype(detail::arg_mapper<buffer_context<Char>>().map(std::declval<T>())),
1538 detail::unformattable>::value>;
1539
1540 /**
1541 \rst
1542 An array of references to arguments. It can be implicitly converted into
1543 `~axom::fmt::basic_format_args` for passing into type-erased formatting functions
1544 such as `~axom::fmt::vformat`.
1545 \endrst
1546 */
1547 template <typename Context, typename... Args>
1548 class format_arg_store
1549 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
1550 // Workaround a GCC template argument substitution bug.
1551 : public basic_format_args<Context>
1552 #endif
1553 {
1554 private:
1555 static const size_t num_args = sizeof...(Args);
1556 static const size_t num_named_args = detail::count_named_args<Args...>();
1557 static const bool is_packed = num_args <= detail::max_packed_args;
1558
1559 using value_type = conditional_t<is_packed, detail::value<Context>,
1560 basic_format_arg<Context>>;
1561
1562 detail::arg_data<value_type, typename Context::char_type, num_args,
1563 num_named_args>
1564 data_;
1565
1566 friend class basic_format_args<Context>;
1567
1568 static constexpr unsigned long long desc =
1569 (is_packed ? detail::encode_types<Context, Args...>()
1570 : detail::is_unpacked_bit | num_args) |
1571 (num_named_args != 0
1572 ? static_cast<unsigned long long>(detail::has_named_args_bit)
1573 : 0);
1574
1575 public:
1576 FMT_CONSTEXPR format_arg_store(const Args&... args)
1577 :
1578 #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
1579 basic_format_args<Context>(*this),
1580 #endif
1581 data_{detail::make_arg<
1582 is_packed, Context,
1583 detail::mapped_type_constant<Args, Context>::value>(args)...} {
1584 detail::init_named_args(data_.named_args(), 0, 0, args...);
1585 }
1586 };
1587
1588 /**
1589 \rst
1590 Constructs a `~axom::fmt::format_arg_store` object that contains references to
1591 arguments and can be implicitly converted to `~axom::fmt::format_args`. `Context`
1592 can be omitted in which case it defaults to `~axom::fmt::context`.
1593 See `~axom::fmt::arg` for lifetime considerations.
1594 \endrst
1595 */
1596 template <typename Context = format_context, typename... Args>
1597 constexpr format_arg_store<Context, Args...> make_format_args(
1598 const Args&... args) {
1599 return {args...};
1600 }
1601
1602 /**
1603 \rst
1604 Constructs a `~axom::fmt::format_arg_store` object that contains references
1605 to arguments and can be implicitly converted to `~axom::fmt::format_args`.
1606 If ``format_str`` is a compile-time string then `make_args_checked` checks
1607 its validity at compile time.
1608 \endrst
1609 */
1610 template <typename... Args, typename S, typename Char = char_t<S>>
1611 inline auto make_args_checked(const S& format_str,
1612 const remove_reference_t<Args>&... args)
1613 -> format_arg_store<buffer_context<Char>, remove_reference_t<Args>...> {
1614 static_assert(
1615 detail::count<(
1616 std::is_base_of<detail::view, remove_reference_t<Args>>::value &&
1617 std::is_reference<Args>::value)...>() == 0,
1618 "passing views as lvalues is disallowed");
1619 detail::check_format_string<Args...>(format_str);
1620 return {args...};
1621 }
1622
1623 /**
1624 \rst
1625 Returns a named argument to be used in a formatting function.
1626 It should only be used in a call to a formatting function or
1627 `dynamic_format_arg_store::push_back`.
1628
1629 **Example**::
1630
1631 axom::fmt::print("Elapsed time: {s:.2f} seconds", axom::fmt::arg("s", 1.23));
1632 \endrst
1633 */
1634 template <typename Char, typename T>
1635 inline detail::named_arg<Char, T> arg(const Char* name, const T& arg) {
1636 static_assert(!detail::is_named_arg<T>(), "nested named arguments");
1637 return {name, arg};
1638 }
1639
1640 /**
1641 \rst
1642 A view of a collection of formatting arguments. To avoid lifetime issues it
1643 should only be used as a parameter type in type-erased functions such as
1644 ``vformat``::
1645
1646 void vlog(string_view format_str, format_args args); // OK
1647 format_args args = make_format_args(42); // Error: dangling reference
1648 \endrst
1649 */
1650 template <typename Context> class basic_format_args {
1651 public:
1652 using size_type = int;
1653 using format_arg = basic_format_arg<Context>;
1654
1655 private:
1656 // A descriptor that contains information about formatting arguments.
1657 // If the number of arguments is less or equal to max_packed_args then
1658 // argument types are passed in the descriptor. This reduces binary code size
1659 // per formatting function call.
1660 unsigned long long desc_;
1661 union {
1662 // If is_packed() returns true then argument values are stored in values_;
1663 // otherwise they are stored in args_. This is done to improve cache
1664 // locality and reduce compiled code size since storing larger objects
1665 // may require more code (at least on x86-64) even if the same amount of
1666 // data is actually copied to stack. It saves ~10% on the bloat test.
1667 const detail::value<Context>* values_;
1668 const format_arg* args_;
1669 };
1670
1671 constexpr bool is_packed() const {
1672 return (desc_ & detail::is_unpacked_bit) == 0;
1673 }
1674 bool has_named_args() const {
1675 return (desc_ & detail::has_named_args_bit) != 0;
1676 }
1677
1678 FMT_CONSTEXPR detail::type type(int index) const {
1679 int shift = index * detail::packed_arg_bits;
1680 unsigned int mask = (1 << detail::packed_arg_bits) - 1;
1681 return static_cast<detail::type>((desc_ >> shift) & mask);
1682 }
1683
1684 constexpr basic_format_args(unsigned long long desc,
1685 const detail::value<Context>* values)
1686 : desc_(desc), values_(values) {}
1687 constexpr basic_format_args(unsigned long long desc, const format_arg* args)
1688 : desc_(desc), args_(args) {}
1689
1690 public:
1691 constexpr basic_format_args() : desc_(0), args_(nullptr) {}
1692
1693 /**
1694 \rst
1695 Constructs a `basic_format_args` object from `~axom::fmt::format_arg_store`.
1696 \endrst
1697 */
1698 template <typename... Args>
1699 constexpr FMT_INLINE basic_format_args(
1700 const format_arg_store<Context, Args...>& store)
1701 : basic_format_args(format_arg_store<Context, Args...>::desc,
1702 store.data_.args()) {}
1703
1704 /**
1705 \rst
1706 Constructs a `basic_format_args` object from
1707 `~axom::fmt::dynamic_format_arg_store`.
1708 \endrst
1709 */
1710 constexpr FMT_INLINE basic_format_args(
1711 const dynamic_format_arg_store<Context>& store)
1712 : basic_format_args(store.get_types(), store.data()) {}
1713
1714 /**
1715 \rst
1716 Constructs a `basic_format_args` object from a dynamic set of arguments.
1717 \endrst
1718 */
1719 constexpr basic_format_args(const format_arg* args, int count)
1720 : basic_format_args(detail::is_unpacked_bit | detail::to_unsigned(count),
1721 args) {}
1722
1723 /** Returns the argument with the specified id. */
1724 FMT_CONSTEXPR format_arg get(int id) const {
1725 format_arg arg;
1726 if (!is_packed()) {
1727 if (id < max_size()) arg = args_[id];
1728 return arg;
1729 }
1730 if (id >= detail::max_packed_args) return arg;
1731 arg.type_ = type(id);
1732 if (arg.type_ == detail::type::none_type) return arg;
1733 arg.value_ = values_[id];
1734 return arg;
1735 }
1736
1737 template <typename Char> format_arg get(basic_string_view<Char> name) const {
1738 int id = get_id(name);
1739 return id >= 0 ? get(id) : format_arg();
1740 }
1741
1742 template <typename Char> int get_id(basic_string_view<Char> name) const {
1743 if (!has_named_args()) return -1;
1744 const auto& named_args =
1745 (is_packed() ? values_[-1] : args_[-1].value_).named_args;
1746 for (size_t i = 0; i < named_args.size; ++i) {
1747 if (named_args.data[i].name == name) return named_args.data[i].id;
1748 }
1749 return -1;
1750 }
1751
1752 int max_size() const {
1753 unsigned long long max_packed = detail::max_packed_args;
1754 return static_cast<int>(is_packed() ? max_packed
1755 : desc_ & ~detail::is_unpacked_bit);
1756 }
1757 };
1758
1759 #ifdef FMT_ARM_ABI_COMPATIBILITY
1760 /** An alias to ``basic_format_args<format_context>``. */
1761 // Separate types would result in shorter symbols but break ABI compatibility
1762 // between clang and gcc on ARM (#1919).
1763 using format_args = basic_format_args<format_context>;
1764 using wformat_args = basic_format_args<wformat_context>;
1765 #else
1766 // DEPRECATED! These are kept for ABI compatibility.
1767 // It is a separate type rather than an alias to make symbols readable.
1768 struct format_args : basic_format_args<format_context> {
1769 template <typename... Args>
1770 FMT_INLINE format_args(const Args&... args) : basic_format_args(args...) {}
1771 };
1772 struct wformat_args : basic_format_args<wformat_context> {
1773 using basic_format_args::basic_format_args;
1774 };
1775 #endif
1776
1777 namespace detail {
1778
1779 template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
1780 std::basic_string<Char> vformat(
1781 basic_string_view<Char> format_str,
1782 basic_format_args<buffer_context<type_identity_t<Char>>> args);
1783
1784 FMT_API std::string vformat(string_view format_str, format_args args);
1785
1786 template <typename Char>
1787 void vformat_to(
1788 buffer<Char>& buf, basic_string_view<Char> format_str,
1789 basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args,
1790 detail::locale_ref loc = {});
1791
1792 template <typename Char, typename Args,
1793 FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
1794 inline void vprint_mojibake(std::FILE*, basic_string_view<Char>, const Args&) {}
1795
1796 FMT_API void vprint_mojibake(std::FILE*, string_view, format_args);
1797 #ifndef _WIN32
1798 inline void vprint_mojibake(std::FILE*, string_view, format_args) {}
1799 #endif
1800 } // namespace detail
1801
1802 /** Formats a string and writes the output to ``out``. */
1803 // GCC 8 and earlier cannot handle std::back_insert_iterator<Container> with
1804 // vformat_to<ArgFormatter>(...) overload, so SFINAE on iterator type instead.
1805 template <typename OutputIt, typename S, typename Char = char_t<S>,
1806 bool enable = detail::is_output_iterator<OutputIt, Char>::value>
1807 auto vformat_to(OutputIt out, const S& format_str,
1808 basic_format_args<buffer_context<type_identity_t<Char>>> args)
1809 -> typename std::enable_if<enable, OutputIt>::type {
1810 decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out));
1811 detail::vformat_to(buf, to_string_view(format_str), args);
1812 return detail::get_iterator(buf);
1813 }
1814
1815 /**
1816 \rst
1817 Formats arguments, writes the result to the output iterator ``out`` and returns
1818 the iterator past the end of the output range.
1819
1820 **Example**::
1821
1822 std::vector<char> out;
1823 axom::fmt::format_to(std::back_inserter(out), "{}", 42);
1824 \endrst
1825 */
1826 // We cannot use FMT_ENABLE_IF because of a bug in gcc 8.3.
1827 template <typename OutputIt, typename S, typename... Args,
1828 bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value>
1829 inline auto format_to(OutputIt out, const S& format_str, Args&&... args) ->
1830 typename std::enable_if<enable, OutputIt>::type {
1831 const auto& vargs = axom::fmt::make_args_checked<Args...>(format_str, args...);
1832 return vformat_to(out, to_string_view(format_str), vargs);
1833 }
1834
1835 template <typename OutputIt> struct format_to_n_result {
1836 /** Iterator past the end of the output range. */
1837 OutputIt out;
1838 /** Total (not truncated) output size. */
1839 size_t size;
1840 };
1841
1842 template <typename OutputIt, typename Char, typename... Args,
1843 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)>
1844 inline format_to_n_result<OutputIt> vformat_to_n(
1845 OutputIt out, size_t n, basic_string_view<Char> format_str,
1846 basic_format_args<buffer_context<type_identity_t<Char>>> args) {
1847 detail::iterator_buffer<OutputIt, Char, detail::fixed_buffer_traits> buf(out,
1848 n);
1849 detail::vformat_to(buf, format_str, args);
1850 return {buf.out(), buf.count()};
1851 }
1852
1853 /**
1854 \rst
1855 Formats arguments, writes up to ``n`` characters of the result to the output
1856 iterator ``out`` and returns the total output size and the iterator past the
1857 end of the output range.
1858 \endrst
1859 */
1860 template <typename OutputIt, typename S, typename... Args,
1861 bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value>
1862 inline auto format_to_n(OutputIt out, size_t n, const S& format_str,
1863 const Args&... args) ->
1864 typename std::enable_if<enable, format_to_n_result<OutputIt>>::type {
1865 const auto& vargs = axom::fmt::make_args_checked<Args...>(format_str, args...);
1866 return vformat_to_n(out, n, to_string_view(format_str), vargs);
1867 }
1868
1869 /**
1870 Returns the number of characters in the output of
1871 ``format(format_str, args...)``.
1872 */
1873 template <typename S, typename... Args, typename Char = char_t<S>>
1874 inline size_t formatted_size(const S& format_str, Args&&... args) {
1875 const auto& vargs = axom::fmt::make_args_checked<Args...>(format_str, args...);
1876 detail::counting_buffer<> buf;
1877 detail::vformat_to(buf, to_string_view(format_str), vargs);
1878 return buf.count();
1879 }
1880
1881 template <typename S, typename Char = char_t<S>>
1882 FMT_INLINE std::basic_string<Char> vformat(
1883 const S& format_str,
1884 basic_format_args<buffer_context<type_identity_t<Char>>> args) {
1885 return detail::vformat(to_string_view(format_str), args);
1886 }
1887
1888 /**
1889 \rst
1890 Formats arguments and returns the result as a string.
1891
1892 **Example**::
1893
1894 #include <fmt/core.h>
1895 std::string message = axom::fmt::format("The answer is {}", 42);
1896 \endrst
1897 */
1898 // Pass char_t as a default template parameter instead of using
1899 // std::basic_string<char_t<S>> to reduce the symbol size.
1900 template <typename S, typename... Args, typename Char = char_t<S>,
1901 FMT_ENABLE_IF(!FMT_COMPILE_TIME_CHECKS ||
1902 !std::is_same<Char, char>::value)>
1903 FMT_INLINE std::basic_string<Char> format(const S& format_str, Args&&... args) {
1904 const auto& vargs = axom::fmt::make_args_checked<Args...>(format_str, args...);
1905 return detail::vformat(to_string_view(format_str), vargs);
1906 }
1907
1908 FMT_API void vprint(string_view, format_args);
1909 FMT_API void vprint(std::FILE*, string_view, format_args);
1910
1911 /**
1912 \rst
1913 Formats ``args`` according to specifications in ``format_str`` and writes the
1914 output to the file ``f``. Strings are assumed to be Unicode-encoded unless the
1915 ``FMT_UNICODE`` macro is set to 0.
1916
1917 **Example**::
1918
1919 axom::fmt::print(stderr, "Don't {}!", "panic");
1920 \endrst
1921 */
1922 template <typename S, typename... Args, typename Char = char_t<S>>
1923 inline void print(std::FILE* f, const S& format_str, Args&&... args) {
1924 const auto& vargs = axom::fmt::make_args_checked<Args...>(format_str, args...);
1925 return detail::is_unicode<Char>()
1926 ? vprint(f, to_string_view(format_str), vargs)
1927 : detail::vprint_mojibake(f, to_string_view(format_str), vargs);
1928 }
1929
1930 /**
1931 \rst
1932 Formats ``args`` according to specifications in ``format_str`` and writes
1933 the output to ``stdout``. Strings are assumed to be Unicode-encoded unless
1934 the ``FMT_UNICODE`` macro is set to 0.
1935
1936 **Example**::
1937
1938 axom::fmt::print("Elapsed time: {0:.2f} seconds", 1.23);
1939 \endrst
1940 */
1941 template <typename S, typename... Args, typename Char = char_t<S>>
1942 inline void print(const S& format_str, Args&&... args) {
1943 const auto& vargs = axom::fmt::make_args_checked<Args...>(format_str, args...);
1944 return detail::is_unicode<Char>()
1945 ? vprint(to_string_view(format_str), vargs)
1946 : detail::vprint_mojibake(stdout, to_string_view(format_str),
1947 vargs);
1948 }
1949 FMT_END_NAMESPACE
1950
1951 #endif // FMT_CORE_H_
1952
1953 // Define FMT_DYNAMIC_ARGS to make core.h provide dynamic_format_arg_store
1954 // DEPRECATED! Include fmt/args.h directly instead.
1955 #ifdef FMT_DYNAMIC_ARGS
1956 #include "args.h"
1957 #endif
1958