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