mirror of
				https://github.com/KartKrewDev/RingRacers.git
				synced 2025-10-30 08:01:28 +00:00 
			
		
		
		
	Update thirdparty/fmt to 11.1.0
This commit is contained in:
		
							parent
							
								
									ed2c0c85cc
								
							
						
					
					
						commit
						43de82f35a
					
				
					 15 changed files with 7359 additions and 6834 deletions
				
			
		
							
								
								
									
										2
									
								
								thirdparty/fmt/CMakeLists.txt
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								thirdparty/fmt/CMakeLists.txt
									
										
									
									
										vendored
									
									
								
							|  | @ -1,5 +1,5 @@ | |||
| # Update from https://github.com/fmtlib/fmt | ||||
| # fmt 10.1.1 | ||||
| # fmt 11.1.0 | ||||
| # License: MIT with object code exception | ||||
| 
 | ||||
| add_library(fmt INTERFACE) | ||||
|  |  | |||
							
								
								
									
										172
									
								
								thirdparty/fmt/include/fmt/args.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										172
									
								
								thirdparty/fmt/include/fmt/args.h
									
										
									
									
										vendored
									
									
								
							|  | @ -8,34 +8,39 @@ | |||
| #ifndef FMT_ARGS_H_ | ||||
| #define FMT_ARGS_H_ | ||||
| 
 | ||||
| #include <functional>  // std::reference_wrapper | ||||
| #include <memory>      // std::unique_ptr | ||||
| #include <vector> | ||||
| #ifndef FMT_MODULE | ||||
| #  include <functional>  // std::reference_wrapper
 | ||||
| #  include <memory>      // std::unique_ptr
 | ||||
| #  include <vector> | ||||
| #endif | ||||
| 
 | ||||
| #include "core.h" | ||||
| #include "format.h"  // std_string_view | ||||
| 
 | ||||
| FMT_BEGIN_NAMESPACE | ||||
| 
 | ||||
| namespace detail { | ||||
| 
 | ||||
| template <typename T> struct is_reference_wrapper : std::false_type {}; | ||||
| template <typename T> | ||||
| struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {}; | ||||
| 
 | ||||
| template <typename T> const T& unwrap(const T& v) { return v; } | ||||
| template <typename T> const T& unwrap(const std::reference_wrapper<T>& v) { | ||||
| template <typename T> auto unwrap(const T& v) -> const T& { return v; } | ||||
| template <typename T> | ||||
| auto unwrap(const std::reference_wrapper<T>& v) -> const T& { | ||||
|   return static_cast<const T&>(v); | ||||
| } | ||||
| 
 | ||||
| class dynamic_arg_list { | ||||
|   // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
 | ||||
|   // templates it doesn't complain about inability to deduce single translation
 | ||||
|   // unit for placing vtable. So storage_node_base is made a fake template.
 | ||||
|   template <typename = void> struct node { | ||||
|     virtual ~node() = default; | ||||
|     std::unique_ptr<node<>> next; | ||||
|   }; | ||||
| // node is defined outside dynamic_arg_list to workaround a C2504 bug in MSVC
 | ||||
| // 2022 (v17.10.0).
 | ||||
| //
 | ||||
| // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
 | ||||
| // templates it doesn't complain about inability to deduce single translation
 | ||||
| // unit for placing vtable. So node is made a fake template.
 | ||||
| template <typename = void> struct node { | ||||
|   virtual ~node() = default; | ||||
|   std::unique_ptr<node<>> next; | ||||
| }; | ||||
| 
 | ||||
| class dynamic_arg_list { | ||||
|   template <typename T> struct typed_node : node<> { | ||||
|     T value; | ||||
| 
 | ||||
|  | @ -50,7 +55,7 @@ class dynamic_arg_list { | |||
|   std::unique_ptr<node<>> head_; | ||||
| 
 | ||||
|  public: | ||||
|   template <typename T, typename Arg> const T& push(const Arg& arg) { | ||||
|   template <typename T, typename Arg> auto push(const Arg& arg) -> const T& { | ||||
|     auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg)); | ||||
|     auto& value = new_node->value; | ||||
|     new_node->next = std::move(head_); | ||||
|  | @ -61,28 +66,18 @@ class dynamic_arg_list { | |||
| }  // namespace detail
 | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   A dynamic version of `fmt::format_arg_store`. | ||||
|   It's equipped with a storage to potentially temporary objects which lifetimes | ||||
|   could be shorter than the format arguments object. | ||||
| 
 | ||||
|   It can be implicitly converted into `~fmt::basic_format_args` for passing | ||||
|   into type-erased formatting functions such as `~fmt::vformat`. | ||||
|   \endrst | ||||
|  * A dynamic list of formatting arguments with storage. | ||||
|  * | ||||
|  * It can be implicitly converted into `fmt::basic_format_args` for passing | ||||
|  * into type-erased formatting functions such as `fmt::vformat`. | ||||
|  */ | ||||
| template <typename Context> | ||||
| class dynamic_format_arg_store | ||||
| #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 | ||||
|     // Workaround a GCC template argument substitution bug.
 | ||||
|     : public basic_format_args<Context> | ||||
| #endif | ||||
| { | ||||
| template <typename Context> class dynamic_format_arg_store { | ||||
|  private: | ||||
|   using char_type = typename Context::char_type; | ||||
| 
 | ||||
|   template <typename T> struct need_copy { | ||||
|     static constexpr detail::type mapped_type = | ||||
|         detail::mapped_type_constant<T, Context>::value; | ||||
|         detail::mapped_type_constant<T, char_type>::value; | ||||
| 
 | ||||
|     enum { | ||||
|       value = !(detail::is_reference_wrapper<T>::value || | ||||
|  | @ -95,7 +90,7 @@ class dynamic_format_arg_store | |||
|   }; | ||||
| 
 | ||||
|   template <typename T> | ||||
|   using stored_type = conditional_t< | ||||
|   using stored_t = conditional_t< | ||||
|       std::is_convertible<T, std::basic_string<char_type>>::value && | ||||
|           !detail::is_reference_wrapper<T>::value, | ||||
|       std::basic_string<char_type>, T>; | ||||
|  | @ -110,80 +105,72 @@ class dynamic_format_arg_store | |||
| 
 | ||||
|   friend class basic_format_args<Context>; | ||||
| 
 | ||||
|   unsigned long long get_types() const { | ||||
|     return detail::is_unpacked_bit | data_.size() | | ||||
|            (named_info_.empty() | ||||
|                 ? 0ULL | ||||
|                 : static_cast<unsigned long long>(detail::has_named_args_bit)); | ||||
|   } | ||||
| 
 | ||||
|   const basic_format_arg<Context>* data() const { | ||||
|   auto data() const -> const basic_format_arg<Context>* { | ||||
|     return named_info_.empty() ? data_.data() : data_.data() + 1; | ||||
|   } | ||||
| 
 | ||||
|   template <typename T> void emplace_arg(const T& arg) { | ||||
|     data_.emplace_back(detail::make_arg<Context>(arg)); | ||||
|     data_.emplace_back(arg); | ||||
|   } | ||||
| 
 | ||||
|   template <typename T> | ||||
|   void emplace_arg(const detail::named_arg<char_type, T>& arg) { | ||||
|     if (named_info_.empty()) { | ||||
|       constexpr const detail::named_arg_info<char_type>* zero_ptr{nullptr}; | ||||
|       data_.insert(data_.begin(), {zero_ptr, 0}); | ||||
|     } | ||||
|     data_.emplace_back(detail::make_arg<Context>(detail::unwrap(arg.value))); | ||||
|     if (named_info_.empty()) | ||||
|       data_.insert(data_.begin(), basic_format_arg<Context>(nullptr, 0)); | ||||
|     data_.emplace_back(detail::unwrap(arg.value)); | ||||
|     auto pop_one = [](std::vector<basic_format_arg<Context>>* data) { | ||||
|       data->pop_back(); | ||||
|     }; | ||||
|     std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)> | ||||
|         guard{&data_, pop_one}; | ||||
|     named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)}); | ||||
|     data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; | ||||
|     data_[0] = {named_info_.data(), named_info_.size()}; | ||||
|     guard.release(); | ||||
|   } | ||||
| 
 | ||||
|  public: | ||||
|   constexpr dynamic_format_arg_store() = default; | ||||
| 
 | ||||
|   operator basic_format_args<Context>() const { | ||||
|     return basic_format_args<Context>(data(), static_cast<int>(data_.size()), | ||||
|                                       !named_info_.empty()); | ||||
|   } | ||||
| 
 | ||||
|   /**
 | ||||
|     \rst | ||||
|     Adds an argument into the dynamic store for later passing to a formatting | ||||
|     function. | ||||
| 
 | ||||
|     Note that custom types and string types (but not string views) are copied | ||||
|     into the store dynamically allocating memory if necessary. | ||||
| 
 | ||||
|     **Example**:: | ||||
| 
 | ||||
|       fmt::dynamic_format_arg_store<fmt::format_context> store; | ||||
|       store.push_back(42); | ||||
|       store.push_back("abc"); | ||||
|       store.push_back(1.5f); | ||||
|       std::string result = fmt::vformat("{} and {} and {}", store); | ||||
|     \endrst | ||||
|   */ | ||||
|    * Adds an argument into the dynamic store for later passing to a formatting | ||||
|    * function. | ||||
|    * | ||||
|    * Note that custom types and string types (but not string views) are copied | ||||
|    * into the store dynamically allocating memory if necessary. | ||||
|    * | ||||
|    * **Example**: | ||||
|    * | ||||
|    *     fmt::dynamic_format_arg_store<fmt::format_context> store; | ||||
|    *     store.push_back(42); | ||||
|    *     store.push_back("abc"); | ||||
|    *     store.push_back(1.5f); | ||||
|    *     std::string result = fmt::vformat("{} and {} and {}", store); | ||||
|    */ | ||||
|   template <typename T> void push_back(const T& arg) { | ||||
|     if (detail::const_check(need_copy<T>::value)) | ||||
|       emplace_arg(dynamic_args_.push<stored_type<T>>(arg)); | ||||
|       emplace_arg(dynamic_args_.push<stored_t<T>>(arg)); | ||||
|     else | ||||
|       emplace_arg(detail::unwrap(arg)); | ||||
|   } | ||||
| 
 | ||||
|   /**
 | ||||
|     \rst | ||||
|     Adds a reference to the argument into the dynamic store for later passing to | ||||
|     a formatting function. | ||||
| 
 | ||||
|     **Example**:: | ||||
| 
 | ||||
|       fmt::dynamic_format_arg_store<fmt::format_context> store; | ||||
|       char band[] = "Rolling Stones"; | ||||
|       store.push_back(std::cref(band)); | ||||
|       band[9] = 'c'; // Changing str affects the output.
 | ||||
|       std::string result = fmt::vformat("{}", store); | ||||
|       // result == "Rolling Scones"
 | ||||
|     \endrst | ||||
|   */ | ||||
|    * Adds a reference to the argument into the dynamic store for later passing | ||||
|    * to a formatting function. | ||||
|    * | ||||
|    * **Example**: | ||||
|    * | ||||
|    *     fmt::dynamic_format_arg_store<fmt::format_context> store; | ||||
|    *     char band[] = "Rolling Stones"; | ||||
|    *     store.push_back(std::cref(band)); | ||||
|    *     band[9] = 'c'; // Changing str affects the output.
 | ||||
|    *     std::string result = fmt::vformat("{}", store); | ||||
|    *     // result == "Rolling Scones"
 | ||||
|    */ | ||||
|   template <typename T> void push_back(std::reference_wrapper<T> arg) { | ||||
|     static_assert( | ||||
|         need_copy<T>::value, | ||||
|  | @ -192,41 +179,40 @@ class dynamic_format_arg_store | |||
|   } | ||||
| 
 | ||||
|   /**
 | ||||
|     Adds named argument into the dynamic store for later passing to a formatting | ||||
|     function. ``std::reference_wrapper`` is supported to avoid copying of the | ||||
|     argument. The name is always copied into the store. | ||||
|   */ | ||||
|    * Adds named argument into the dynamic store for later passing to a | ||||
|    * formatting function. `std::reference_wrapper` is supported to avoid | ||||
|    * copying of the argument. The name is always copied into the store. | ||||
|    */ | ||||
|   template <typename T> | ||||
|   void push_back(const detail::named_arg<char_type, T>& arg) { | ||||
|     const char_type* arg_name = | ||||
|         dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str(); | ||||
|     if (detail::const_check(need_copy<T>::value)) { | ||||
|       emplace_arg( | ||||
|           fmt::arg(arg_name, dynamic_args_.push<stored_type<T>>(arg.value))); | ||||
|           fmt::arg(arg_name, dynamic_args_.push<stored_t<T>>(arg.value))); | ||||
|     } else { | ||||
|       emplace_arg(fmt::arg(arg_name, arg.value)); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** Erase all elements from the store */ | ||||
|   /// Erase all elements from the store.
 | ||||
|   void clear() { | ||||
|     data_.clear(); | ||||
|     named_info_.clear(); | ||||
|     dynamic_args_ = detail::dynamic_arg_list(); | ||||
|     dynamic_args_ = {}; | ||||
|   } | ||||
| 
 | ||||
|   /**
 | ||||
|     \rst | ||||
|     Reserves space to store at least *new_cap* arguments including | ||||
|     *new_cap_named* named arguments. | ||||
|     \endrst | ||||
|   */ | ||||
|   /// Reserves space to store at least `new_cap` arguments including
 | ||||
|   /// `new_cap_named` named arguments.
 | ||||
|   void reserve(size_t new_cap, size_t new_cap_named) { | ||||
|     FMT_ASSERT(new_cap >= new_cap_named, | ||||
|                "Set of arguments includes set of named arguments"); | ||||
|                "set of arguments includes set of named arguments"); | ||||
|     data_.reserve(new_cap); | ||||
|     named_info_.reserve(new_cap_named); | ||||
|   } | ||||
| 
 | ||||
|   /// Returns the number of elements in the store.
 | ||||
|   size_t size() const noexcept { return data_.size(); } | ||||
| }; | ||||
| 
 | ||||
| FMT_END_NAMESPACE | ||||
|  |  | |||
							
								
								
									
										2938
									
								
								thirdparty/fmt/include/fmt/base.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2938
									
								
								thirdparty/fmt/include/fmt/base.h
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										1408
									
								
								thirdparty/fmt/include/fmt/chrono.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1408
									
								
								thirdparty/fmt/include/fmt/chrono.h
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										264
									
								
								thirdparty/fmt/include/fmt/color.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										264
									
								
								thirdparty/fmt/include/fmt/color.h
									
										
									
									
										vendored
									
									
								
							|  | @ -227,19 +227,19 @@ struct color_type { | |||
| }; | ||||
| }  // namespace detail
 | ||||
| 
 | ||||
| /** A text style consisting of foreground and background colors and emphasis. */ | ||||
| /// A text style consisting of foreground and background colors and emphasis.
 | ||||
| class text_style { | ||||
|  public: | ||||
|   FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept | ||||
|       : set_foreground_color(), set_background_color(), ems(em) {} | ||||
| 
 | ||||
|   FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) { | ||||
|   FMT_CONSTEXPR auto operator|=(const text_style& rhs) -> text_style& { | ||||
|     if (!set_foreground_color) { | ||||
|       set_foreground_color = rhs.set_foreground_color; | ||||
|       foreground_color = rhs.foreground_color; | ||||
|     } else if (rhs.set_foreground_color) { | ||||
|       if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) | ||||
|         FMT_THROW(format_error("can't OR a terminal color")); | ||||
|         report_error("can't OR a terminal color"); | ||||
|       foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color; | ||||
|     } | ||||
| 
 | ||||
|  | @ -248,7 +248,7 @@ class text_style { | |||
|       background_color = rhs.background_color; | ||||
|     } else if (rhs.set_background_color) { | ||||
|       if (!background_color.is_rgb || !rhs.background_color.is_rgb) | ||||
|         FMT_THROW(format_error("can't OR a terminal color")); | ||||
|         report_error("can't OR a terminal color"); | ||||
|       background_color.value.rgb_color |= rhs.background_color.value.rgb_color; | ||||
|     } | ||||
| 
 | ||||
|  | @ -257,29 +257,29 @@ class text_style { | |||
|     return *this; | ||||
|   } | ||||
| 
 | ||||
|   friend FMT_CONSTEXPR text_style operator|(text_style lhs, | ||||
|                                             const text_style& rhs) { | ||||
|   friend FMT_CONSTEXPR auto operator|(text_style lhs, const text_style& rhs) | ||||
|       -> text_style { | ||||
|     return lhs |= rhs; | ||||
|   } | ||||
| 
 | ||||
|   FMT_CONSTEXPR bool has_foreground() const noexcept { | ||||
|   FMT_CONSTEXPR auto has_foreground() const noexcept -> bool { | ||||
|     return set_foreground_color; | ||||
|   } | ||||
|   FMT_CONSTEXPR bool has_background() const noexcept { | ||||
|   FMT_CONSTEXPR auto has_background() const noexcept -> bool { | ||||
|     return set_background_color; | ||||
|   } | ||||
|   FMT_CONSTEXPR bool has_emphasis() const noexcept { | ||||
|   FMT_CONSTEXPR auto has_emphasis() const noexcept -> bool { | ||||
|     return static_cast<uint8_t>(ems) != 0; | ||||
|   } | ||||
|   FMT_CONSTEXPR detail::color_type get_foreground() const noexcept { | ||||
|   FMT_CONSTEXPR auto get_foreground() const noexcept -> detail::color_type { | ||||
|     FMT_ASSERT(has_foreground(), "no foreground specified for this style"); | ||||
|     return foreground_color; | ||||
|   } | ||||
|   FMT_CONSTEXPR detail::color_type get_background() const noexcept { | ||||
|   FMT_CONSTEXPR auto get_background() const noexcept -> detail::color_type { | ||||
|     FMT_ASSERT(has_background(), "no background specified for this style"); | ||||
|     return background_color; | ||||
|   } | ||||
|   FMT_CONSTEXPR emphasis get_emphasis() const noexcept { | ||||
|   FMT_CONSTEXPR auto get_emphasis() const noexcept -> emphasis { | ||||
|     FMT_ASSERT(has_emphasis(), "no emphasis specified for this style"); | ||||
|     return ems; | ||||
|   } | ||||
|  | @ -297,9 +297,11 @@ class text_style { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   friend FMT_CONSTEXPR text_style fg(detail::color_type foreground) noexcept; | ||||
|   friend FMT_CONSTEXPR auto fg(detail::color_type foreground) noexcept | ||||
|       -> text_style; | ||||
| 
 | ||||
|   friend FMT_CONSTEXPR text_style bg(detail::color_type background) noexcept; | ||||
|   friend FMT_CONSTEXPR auto bg(detail::color_type background) noexcept | ||||
|       -> text_style; | ||||
| 
 | ||||
|   detail::color_type foreground_color; | ||||
|   detail::color_type background_color; | ||||
|  | @ -308,24 +310,27 @@ class text_style { | |||
|   emphasis ems; | ||||
| }; | ||||
| 
 | ||||
| /** Creates a text style from the foreground (text) color. */ | ||||
| FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) noexcept { | ||||
| /// Creates a text style from the foreground (text) color.
 | ||||
| FMT_CONSTEXPR inline auto fg(detail::color_type foreground) noexcept | ||||
|     -> text_style { | ||||
|   return text_style(true, foreground); | ||||
| } | ||||
| 
 | ||||
| /** Creates a text style from the background color. */ | ||||
| FMT_CONSTEXPR inline text_style bg(detail::color_type background) noexcept { | ||||
| /// Creates a text style from the background color.
 | ||||
| FMT_CONSTEXPR inline auto bg(detail::color_type background) noexcept | ||||
|     -> text_style { | ||||
|   return text_style(false, background); | ||||
| } | ||||
| 
 | ||||
| FMT_CONSTEXPR inline text_style operator|(emphasis lhs, emphasis rhs) noexcept { | ||||
| FMT_CONSTEXPR inline auto operator|(emphasis lhs, emphasis rhs) noexcept | ||||
|     -> text_style { | ||||
|   return text_style(lhs) | rhs; | ||||
| } | ||||
| 
 | ||||
| namespace detail { | ||||
| 
 | ||||
| template <typename Char> struct ansi_color_escape { | ||||
|   FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color, | ||||
|   FMT_CONSTEXPR ansi_color_escape(color_type text_color, | ||||
|                                   const char* esc) noexcept { | ||||
|     // If we have a terminal color, we need to output another escape code
 | ||||
|     // sequence.
 | ||||
|  | @ -384,9 +389,9 @@ template <typename Char> struct ansi_color_escape { | |||
|   } | ||||
|   FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; } | ||||
| 
 | ||||
|   FMT_CONSTEXPR const Char* begin() const noexcept { return buffer; } | ||||
|   FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const noexcept { | ||||
|     return buffer + std::char_traits<Char>::length(buffer); | ||||
|   FMT_CONSTEXPR auto begin() const noexcept -> const Char* { return buffer; } | ||||
|   FMT_CONSTEXPR20 auto end() const noexcept -> const Char* { | ||||
|     return buffer + basic_string_view<Char>(buffer).size(); | ||||
|   } | ||||
| 
 | ||||
|  private: | ||||
|  | @ -400,25 +405,27 @@ template <typename Char> struct ansi_color_escape { | |||
|     out[2] = static_cast<Char>('0' + c % 10); | ||||
|     out[3] = static_cast<Char>(delimiter); | ||||
|   } | ||||
|   static FMT_CONSTEXPR bool has_emphasis(emphasis em, emphasis mask) noexcept { | ||||
|   static FMT_CONSTEXPR auto has_emphasis(emphasis em, emphasis mask) noexcept | ||||
|       -> bool { | ||||
|     return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename Char> | ||||
| FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color( | ||||
|     detail::color_type foreground) noexcept { | ||||
| FMT_CONSTEXPR auto make_foreground_color(color_type foreground) noexcept | ||||
|     -> ansi_color_escape<Char> { | ||||
|   return ansi_color_escape<Char>(foreground, "\x1b[38;2;"); | ||||
| } | ||||
| 
 | ||||
| template <typename Char> | ||||
| FMT_CONSTEXPR ansi_color_escape<Char> make_background_color( | ||||
|     detail::color_type background) noexcept { | ||||
| FMT_CONSTEXPR auto make_background_color(color_type background) noexcept | ||||
|     -> ansi_color_escape<Char> { | ||||
|   return ansi_color_escape<Char>(background, "\x1b[48;2;"); | ||||
| } | ||||
| 
 | ||||
| template <typename Char> | ||||
| FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) noexcept { | ||||
| FMT_CONSTEXPR auto make_emphasis(emphasis em) noexcept | ||||
|     -> ansi_color_escape<Char> { | ||||
|   return ansi_color_escape<Char>(em); | ||||
| } | ||||
| 
 | ||||
|  | @ -427,149 +434,123 @@ template <typename Char> inline void reset_color(buffer<Char>& buffer) { | |||
|   buffer.append(reset_color.begin(), reset_color.end()); | ||||
| } | ||||
| 
 | ||||
| template <typename T> struct styled_arg { | ||||
| template <typename T> struct styled_arg : view { | ||||
|   const T& value; | ||||
|   text_style style; | ||||
|   styled_arg(const T& v, text_style s) : value(v), style(s) {} | ||||
| }; | ||||
| 
 | ||||
| template <typename Char> | ||||
| void vformat_to(buffer<Char>& buf, const text_style& ts, | ||||
|                 basic_string_view<Char> format_str, | ||||
|                 basic_format_args<buffer_context<type_identity_t<Char>>> args) { | ||||
|                 basic_string_view<Char> fmt, | ||||
|                 basic_format_args<buffered_context<Char>> args) { | ||||
|   bool has_style = false; | ||||
|   if (ts.has_emphasis()) { | ||||
|     has_style = true; | ||||
|     auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis()); | ||||
|     auto emphasis = make_emphasis<Char>(ts.get_emphasis()); | ||||
|     buf.append(emphasis.begin(), emphasis.end()); | ||||
|   } | ||||
|   if (ts.has_foreground()) { | ||||
|     has_style = true; | ||||
|     auto foreground = detail::make_foreground_color<Char>(ts.get_foreground()); | ||||
|     auto foreground = make_foreground_color<Char>(ts.get_foreground()); | ||||
|     buf.append(foreground.begin(), foreground.end()); | ||||
|   } | ||||
|   if (ts.has_background()) { | ||||
|     has_style = true; | ||||
|     auto background = detail::make_background_color<Char>(ts.get_background()); | ||||
|     auto background = make_background_color<Char>(ts.get_background()); | ||||
|     buf.append(background.begin(), background.end()); | ||||
|   } | ||||
|   detail::vformat_to(buf, format_str, args, {}); | ||||
|   if (has_style) detail::reset_color<Char>(buf); | ||||
|   vformat_to(buf, fmt, args); | ||||
|   if (has_style) reset_color<Char>(buf); | ||||
| } | ||||
| 
 | ||||
| }  // namespace detail
 | ||||
| 
 | ||||
| inline void vprint(std::FILE* f, const text_style& ts, string_view fmt, | ||||
| inline void vprint(FILE* f, const text_style& ts, string_view fmt, | ||||
|                    format_args args) { | ||||
|   // Legacy wide streams are not supported.
 | ||||
|   auto buf = memory_buffer(); | ||||
|   detail::vformat_to(buf, ts, fmt, args); | ||||
|   if (detail::is_utf8()) { | ||||
|     detail::print(f, string_view(buf.begin(), buf.size())); | ||||
|     return; | ||||
|   } | ||||
|   buf.push_back('\0'); | ||||
|   int result = std::fputs(buf.data(), f); | ||||
|   if (result < 0) | ||||
|     FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); | ||||
|   print(f, FMT_STRING("{}"), string_view(buf.begin(), buf.size())); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Formats a string and prints it to the specified file stream using ANSI | ||||
|   escape sequences to specify text formatting. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     fmt::print(fmt::emphasis::bold | fg(fmt::color::red), | ||||
|                "Elapsed time: {0:.2f} seconds", 1.23); | ||||
|   \endrst | ||||
|  * Formats a string and prints it to the specified file stream using ANSI | ||||
|  * escape sequences to specify text formatting. | ||||
|  * | ||||
|  * **Example**: | ||||
|  * | ||||
|  *     fmt::print(fmt::emphasis::bold | fg(fmt::color::red), | ||||
|  *                "Elapsed time: {0:.2f} seconds", 1.23); | ||||
|  */ | ||||
| template <typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_string<S>::value)> | ||||
| void print(std::FILE* f, const text_style& ts, const S& format_str, | ||||
|            const Args&... args) { | ||||
|   vprint(f, ts, format_str, | ||||
|          fmt::make_format_args<buffer_context<char_t<S>>>(args...)); | ||||
| template <typename... T> | ||||
| void print(FILE* f, const text_style& ts, format_string<T...> fmt, | ||||
|            T&&... args) { | ||||
|   vprint(f, ts, fmt.str, vargs<T...>{{args...}}); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Formats a string and prints it to stdout using ANSI escape sequences to | ||||
|   specify text formatting. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     fmt::print(fmt::emphasis::bold | fg(fmt::color::red), | ||||
|                "Elapsed time: {0:.2f} seconds", 1.23); | ||||
|   \endrst | ||||
|  * Formats a string and prints it to stdout using ANSI escape sequences to | ||||
|  * specify text formatting. | ||||
|  * | ||||
|  * **Example**: | ||||
|  * | ||||
|  *     fmt::print(fmt::emphasis::bold | fg(fmt::color::red), | ||||
|  *                "Elapsed time: {0:.2f} seconds", 1.23); | ||||
|  */ | ||||
| template <typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_string<S>::value)> | ||||
| void print(const text_style& ts, const S& format_str, const Args&... args) { | ||||
|   return print(stdout, ts, format_str, args...); | ||||
| template <typename... T> | ||||
| void print(const text_style& ts, format_string<T...> fmt, T&&... args) { | ||||
|   return print(stdout, ts, fmt, std::forward<T>(args)...); | ||||
| } | ||||
| 
 | ||||
| template <typename S, typename Char = char_t<S>> | ||||
| inline std::basic_string<Char> vformat( | ||||
|     const text_style& ts, const S& format_str, | ||||
|     basic_format_args<buffer_context<type_identity_t<Char>>> args) { | ||||
|   basic_memory_buffer<Char> buf; | ||||
|   detail::vformat_to(buf, ts, detail::to_string_view(format_str), args); | ||||
| inline auto vformat(const text_style& ts, string_view fmt, format_args args) | ||||
|     -> std::string { | ||||
|   auto buf = memory_buffer(); | ||||
|   detail::vformat_to(buf, ts, fmt, args); | ||||
|   return fmt::to_string(buf); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Formats arguments and returns the result as a string using ANSI | ||||
|   escape sequences to specify text formatting. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     #include <fmt/color.h> | ||||
|     std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), | ||||
|                                       "The answer is {}", 42); | ||||
|   \endrst | ||||
| */ | ||||
| template <typename S, typename... Args, typename Char = char_t<S>> | ||||
| inline std::basic_string<Char> format(const text_style& ts, const S& format_str, | ||||
|                                       const Args&... args) { | ||||
|   return fmt::vformat(ts, detail::to_string_view(format_str), | ||||
|                       fmt::make_format_args<buffer_context<Char>>(args...)); | ||||
|  * Formats arguments and returns the result as a string using ANSI escape | ||||
|  * sequences to specify text formatting. | ||||
|  * | ||||
|  * **Example**: | ||||
|  * | ||||
|  * ``` | ||||
|  * #include <fmt/color.h> | ||||
|  * std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), | ||||
|  *                                   "The answer is {}", 42); | ||||
|  * ``` | ||||
|  */ | ||||
| template <typename... T> | ||||
| inline auto format(const text_style& ts, format_string<T...> fmt, T&&... args) | ||||
|     -> std::string { | ||||
|   return fmt::vformat(ts, fmt.str, vargs<T...>{{args...}}); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   Formats a string with the given text_style and writes the output to ``out``. | ||||
|  */ | ||||
| template <typename OutputIt, typename Char, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)> | ||||
| OutputIt vformat_to( | ||||
|     OutputIt out, const text_style& ts, basic_string_view<Char> format_str, | ||||
|     basic_format_args<buffer_context<type_identity_t<Char>>> args) { | ||||
|   auto&& buf = detail::get_buffer<Char>(out); | ||||
|   detail::vformat_to(buf, ts, format_str, args); | ||||
| /// Formats a string with the given text_style and writes the output to `out`.
 | ||||
| template <typename OutputIt, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)> | ||||
| auto vformat_to(OutputIt out, const text_style& ts, string_view fmt, | ||||
|                 format_args args) -> OutputIt { | ||||
|   auto&& buf = detail::get_buffer<char>(out); | ||||
|   detail::vformat_to(buf, ts, fmt, args); | ||||
|   return detail::get_iterator(buf, out); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Formats arguments with the given text_style, writes the result to the output | ||||
|   iterator ``out`` and returns the iterator past the end of the output range. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     std::vector<char> out; | ||||
|     fmt::format_to(std::back_inserter(out), | ||||
|                    fmt::emphasis::bold | fg(fmt::color::red), "{}", 42); | ||||
|   \endrst | ||||
| */ | ||||
| template <typename OutputIt, typename S, typename... Args, | ||||
|           bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value&& | ||||
|               detail::is_string<S>::value> | ||||
| inline auto format_to(OutputIt out, const text_style& ts, const S& format_str, | ||||
|                       Args&&... args) -> | ||||
|     typename std::enable_if<enable, OutputIt>::type { | ||||
|   return vformat_to(out, ts, detail::to_string_view(format_str), | ||||
|                     fmt::make_format_args<buffer_context<char_t<S>>>(args...)); | ||||
|  * Formats arguments with the given text style, writes the result to the output | ||||
|  * iterator `out` and returns the iterator past the end of the output range. | ||||
|  * | ||||
|  * **Example**: | ||||
|  * | ||||
|  *     std::vector<char> out; | ||||
|  *     fmt::format_to(std::back_inserter(out), | ||||
|  *                    fmt::emphasis::bold | fg(fmt::color::red), "{}", 42); | ||||
|  */ | ||||
| template <typename OutputIt, typename... T, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)> | ||||
| inline auto format_to(OutputIt out, const text_style& ts, | ||||
|                       format_string<T...> fmt, T&&... args) -> OutputIt { | ||||
|   return vformat_to(out, ts, fmt.str, vargs<T...>{{args...}}); | ||||
| } | ||||
| 
 | ||||
| template <typename T, typename Char> | ||||
|  | @ -578,47 +559,44 @@ struct formatter<detail::styled_arg<T>, Char> : formatter<T, Char> { | |||
|   auto format(const detail::styled_arg<T>& arg, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     const auto& ts = arg.style; | ||||
|     const auto& value = arg.value; | ||||
|     auto out = ctx.out(); | ||||
| 
 | ||||
|     bool has_style = false; | ||||
|     if (ts.has_emphasis()) { | ||||
|       has_style = true; | ||||
|       auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis()); | ||||
|       out = std::copy(emphasis.begin(), emphasis.end(), out); | ||||
|       out = detail::copy<Char>(emphasis.begin(), emphasis.end(), out); | ||||
|     } | ||||
|     if (ts.has_foreground()) { | ||||
|       has_style = true; | ||||
|       auto foreground = | ||||
|           detail::make_foreground_color<Char>(ts.get_foreground()); | ||||
|       out = std::copy(foreground.begin(), foreground.end(), out); | ||||
|       out = detail::copy<Char>(foreground.begin(), foreground.end(), out); | ||||
|     } | ||||
|     if (ts.has_background()) { | ||||
|       has_style = true; | ||||
|       auto background = | ||||
|           detail::make_background_color<Char>(ts.get_background()); | ||||
|       out = std::copy(background.begin(), background.end(), out); | ||||
|       out = detail::copy<Char>(background.begin(), background.end(), out); | ||||
|     } | ||||
|     out = formatter<T, Char>::format(value, ctx); | ||||
|     out = formatter<T, Char>::format(arg.value, ctx); | ||||
|     if (has_style) { | ||||
|       auto reset_color = string_view("\x1b[0m"); | ||||
|       out = std::copy(reset_color.begin(), reset_color.end(), out); | ||||
|       out = detail::copy<Char>(reset_color.begin(), reset_color.end(), out); | ||||
|     } | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Returns an argument that will be formatted using ANSI escape sequences, | ||||
|   to be used in a formatting function. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     fmt::print("Elapsed time: {0:.2f} seconds", | ||||
|                fmt::styled(1.23, fmt::fg(fmt::color::green) | | ||||
|                                  fmt::bg(fmt::color::blue))); | ||||
|   \endrst | ||||
|  * Returns an argument that will be formatted using ANSI escape sequences, | ||||
|  * to be used in a formatting function. | ||||
|  * | ||||
|  * **Example**: | ||||
|  * | ||||
|  *     fmt::print("Elapsed time: {0:.2f} seconds", | ||||
|  *                fmt::styled(1.23, fmt::fg(fmt::color::green) | | ||||
|  *                                  fmt::bg(fmt::color::blue))); | ||||
|  */ | ||||
| template <typename T> | ||||
| FMT_CONSTEXPR auto styled(const T& value, text_style ts) | ||||
|  |  | |||
							
								
								
									
										169
									
								
								thirdparty/fmt/include/fmt/compile.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										169
									
								
								thirdparty/fmt/include/fmt/compile.h
									
										
									
									
										vendored
									
									
								
							|  | @ -8,56 +8,51 @@ | |||
| #ifndef FMT_COMPILE_H_ | ||||
| #define FMT_COMPILE_H_ | ||||
| 
 | ||||
| #ifndef FMT_MODULE | ||||
| #  include <iterator>  // std::back_inserter
 | ||||
| #endif | ||||
| 
 | ||||
| #include "format.h" | ||||
| 
 | ||||
| FMT_BEGIN_NAMESPACE | ||||
| namespace detail { | ||||
| 
 | ||||
| template <typename Char, typename InputIt> | ||||
| FMT_CONSTEXPR inline counting_iterator copy_str(InputIt begin, InputIt end, | ||||
|                                                 counting_iterator it) { | ||||
|   return it + (end - begin); | ||||
| } | ||||
| 
 | ||||
| // A compile-time string which is compiled into fast formatting code.
 | ||||
| class compiled_string {}; | ||||
| FMT_EXPORT class compiled_string {}; | ||||
| 
 | ||||
| namespace detail { | ||||
| 
 | ||||
| template <typename S> | ||||
| struct is_compiled_string : std::is_base_of<compiled_string, S> {}; | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Converts a string literal *s* into a format string that will be parsed at | ||||
|   compile time and converted into efficient formatting code. Requires C++17 | ||||
|   ``constexpr if`` compiler support. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     // Converts 42 into std::string using the most efficient method and no
 | ||||
|     // runtime format string processing.
 | ||||
|     std::string s = fmt::format(FMT_COMPILE("{}"), 42); | ||||
|   \endrst | ||||
|  * Converts a string literal `s` into a format string that will be parsed at | ||||
|  * compile time and converted into efficient formatting code. Requires C++17 | ||||
|  * `constexpr if` compiler support. | ||||
|  * | ||||
|  * **Example**: | ||||
|  * | ||||
|  *     // Converts 42 into std::string using the most efficient method and no
 | ||||
|  *     // runtime format string processing.
 | ||||
|  *     std::string s = fmt::format(FMT_COMPILE("{}"), 42); | ||||
|  */ | ||||
| #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) | ||||
| #  define FMT_COMPILE(s) \ | ||||
|     FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit) | ||||
| #  define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::compiled_string) | ||||
| #else | ||||
| #  define FMT_COMPILE(s) FMT_STRING(s) | ||||
| #endif | ||||
| 
 | ||||
| #if FMT_USE_NONTYPE_TEMPLATE_ARGS | ||||
| template <typename Char, size_t N, | ||||
|           fmt::detail_exported::fixed_string<Char, N> Str> | ||||
| template <typename Char, size_t N, fmt::detail::fixed_string<Char, N> Str> | ||||
| struct udl_compiled_string : compiled_string { | ||||
|   using char_type = Char; | ||||
|   explicit constexpr operator basic_string_view<char_type>() const { | ||||
|   constexpr explicit operator basic_string_view<char_type>() const { | ||||
|     return {Str.data, N - 1}; | ||||
|   } | ||||
| }; | ||||
| #endif | ||||
| 
 | ||||
| template <typename T, typename... Tail> | ||||
| const T& first(const T& value, const Tail&...) { | ||||
| auto first(const T& value, const Tail&...) -> const T& { | ||||
|   return value; | ||||
| } | ||||
| 
 | ||||
|  | @ -75,6 +70,29 @@ constexpr const auto& get([[maybe_unused]] const T& first, | |||
|     return detail::get<N - 1>(rest...); | ||||
| } | ||||
| 
 | ||||
| #  if FMT_USE_NONTYPE_TEMPLATE_ARGS | ||||
| template <int N, typename T, typename... Args, typename Char> | ||||
| constexpr auto get_arg_index_by_name(basic_string_view<Char> name) -> int { | ||||
|   if constexpr (is_static_named_arg<T>()) { | ||||
|     if (name == T::name) return N; | ||||
|   } | ||||
|   if constexpr (sizeof...(Args) > 0) | ||||
|     return get_arg_index_by_name<N + 1, Args...>(name); | ||||
|   (void)name;  // Workaround an MSVC bug about "unused" parameter.
 | ||||
|   return -1; | ||||
| } | ||||
| #  endif | ||||
| 
 | ||||
| template <typename... Args, typename Char> | ||||
| FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view<Char> name) -> int { | ||||
| #  if FMT_USE_NONTYPE_TEMPLATE_ARGS | ||||
|   if constexpr (sizeof...(Args) > 0) | ||||
|     return get_arg_index_by_name<0, Args...>(name); | ||||
| #  endif | ||||
|   (void)name; | ||||
|   return -1; | ||||
| } | ||||
| 
 | ||||
| template <typename Char, typename... Args> | ||||
| constexpr int get_arg_index_by_name(basic_string_view<Char> name, | ||||
|                                     type_list<Args...>) { | ||||
|  | @ -144,11 +162,12 @@ template <typename Char, typename T, int N> struct field { | |||
|   template <typename OutputIt, typename... Args> | ||||
|   constexpr OutputIt format(OutputIt out, const Args&... args) const { | ||||
|     const T& arg = get_arg_checked<T, N>(args...); | ||||
|     if constexpr (std::is_convertible_v<T, basic_string_view<Char>>) { | ||||
|     if constexpr (std::is_convertible<T, basic_string_view<Char>>::value) { | ||||
|       auto s = basic_string_view<Char>(arg); | ||||
|       return copy_str<Char>(s.begin(), s.end(), out); | ||||
|       return copy<Char>(s.begin(), s.end(), out); | ||||
|     } else { | ||||
|       return write<Char>(out, arg); | ||||
|     } | ||||
|     return write<Char>(out, arg); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
|  | @ -236,13 +255,12 @@ constexpr size_t parse_text(basic_string_view<Char> str, size_t pos) { | |||
| } | ||||
| 
 | ||||
| template <typename Args, size_t POS, int ID, typename S> | ||||
| constexpr auto compile_format_string(S format_str); | ||||
| constexpr auto compile_format_string(S fmt); | ||||
| 
 | ||||
| template <typename Args, size_t POS, int ID, typename T, typename S> | ||||
| constexpr auto parse_tail(T head, S format_str) { | ||||
|   if constexpr (POS != | ||||
|                 basic_string_view<typename S::char_type>(format_str).size()) { | ||||
|     constexpr auto tail = compile_format_string<Args, POS, ID>(format_str); | ||||
| constexpr auto parse_tail(T head, S fmt) { | ||||
|   if constexpr (POS != basic_string_view<typename S::char_type>(fmt).size()) { | ||||
|     constexpr auto tail = compile_format_string<Args, POS, ID>(fmt); | ||||
|     if constexpr (std::is_same<remove_cvref_t<decltype(tail)>, | ||||
|                                unknown_format>()) | ||||
|       return tail; | ||||
|  | @ -274,6 +292,7 @@ constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str, | |||
| } | ||||
| 
 | ||||
| template <typename Char> struct arg_id_handler { | ||||
|   arg_id_kind kind; | ||||
|   arg_ref<Char> arg_id; | ||||
| 
 | ||||
|   constexpr int on_auto() { | ||||
|  | @ -281,25 +300,28 @@ template <typename Char> struct arg_id_handler { | |||
|     return 0; | ||||
|   } | ||||
|   constexpr int on_index(int id) { | ||||
|     kind = arg_id_kind::index; | ||||
|     arg_id = arg_ref<Char>(id); | ||||
|     return 0; | ||||
|   } | ||||
|   constexpr int on_name(basic_string_view<Char> id) { | ||||
|     kind = arg_id_kind::name; | ||||
|     arg_id = arg_ref<Char>(id); | ||||
|     return 0; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename Char> struct parse_arg_id_result { | ||||
|   arg_id_kind kind; | ||||
|   arg_ref<Char> arg_id; | ||||
|   const Char* arg_id_end; | ||||
| }; | ||||
| 
 | ||||
| template <int ID, typename Char> | ||||
| constexpr auto parse_arg_id(const Char* begin, const Char* end) { | ||||
|   auto handler = arg_id_handler<Char>{arg_ref<Char>{}}; | ||||
|   auto handler = arg_id_handler<Char>{arg_id_kind::none, arg_ref<Char>{}}; | ||||
|   auto arg_id_end = parse_arg_id(begin, end, handler); | ||||
|   return parse_arg_id_result<Char>{handler.arg_id, arg_id_end}; | ||||
|   return parse_arg_id_result<Char>{handler.kind, handler.arg_id, arg_id_end}; | ||||
| } | ||||
| 
 | ||||
| template <typename T, typename Enable = void> struct field_type { | ||||
|  | @ -313,14 +335,13 @@ struct field_type<T, enable_if_t<detail::is_named_arg<T>::value>> { | |||
| 
 | ||||
| template <typename T, typename Args, size_t END_POS, int ARG_INDEX, int NEXT_ID, | ||||
|           typename S> | ||||
| constexpr auto parse_replacement_field_then_tail(S format_str) { | ||||
| constexpr auto parse_replacement_field_then_tail(S fmt) { | ||||
|   using char_type = typename S::char_type; | ||||
|   constexpr auto str = basic_string_view<char_type>(format_str); | ||||
|   constexpr auto str = basic_string_view<char_type>(fmt); | ||||
|   constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type(); | ||||
|   if constexpr (c == '}') { | ||||
|     return parse_tail<Args, END_POS + 1, NEXT_ID>( | ||||
|         field<char_type, typename field_type<T>::type, ARG_INDEX>(), | ||||
|         format_str); | ||||
|         field<char_type, typename field_type<T>::type, ARG_INDEX>(), fmt); | ||||
|   } else if constexpr (c != ':') { | ||||
|     FMT_THROW(format_error("expected ':'")); | ||||
|   } else { | ||||
|  | @ -333,7 +354,7 @@ constexpr auto parse_replacement_field_then_tail(S format_str) { | |||
|       return parse_tail<Args, result.end + 1, result.next_arg_id>( | ||||
|           spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{ | ||||
|               result.fmt}, | ||||
|           format_str); | ||||
|           fmt); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | @ -341,22 +362,21 @@ constexpr auto parse_replacement_field_then_tail(S format_str) { | |||
| // Compiles a non-empty format string and returns the compiled representation
 | ||||
| // or unknown_format() on unrecognized input.
 | ||||
| template <typename Args, size_t POS, int ID, typename S> | ||||
| constexpr auto compile_format_string(S format_str) { | ||||
| constexpr auto compile_format_string(S fmt) { | ||||
|   using char_type = typename S::char_type; | ||||
|   constexpr auto str = basic_string_view<char_type>(format_str); | ||||
|   constexpr auto str = basic_string_view<char_type>(fmt); | ||||
|   if constexpr (str[POS] == '{') { | ||||
|     if constexpr (POS + 1 == str.size()) | ||||
|       FMT_THROW(format_error("unmatched '{' in format string")); | ||||
|     if constexpr (str[POS + 1] == '{') { | ||||
|       return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str); | ||||
|       return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), fmt); | ||||
|     } else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') { | ||||
|       static_assert(ID != manual_indexing_id, | ||||
|                     "cannot switch from manual to automatic argument indexing"); | ||||
|       constexpr auto next_id = | ||||
|           ID != manual_indexing_id ? ID + 1 : manual_indexing_id; | ||||
|       return parse_replacement_field_then_tail<get_type<ID, Args>, Args, | ||||
|                                                POS + 1, ID, next_id>( | ||||
|           format_str); | ||||
|                                                POS + 1, ID, next_id>(fmt); | ||||
|     } else { | ||||
|       constexpr auto arg_id_result = | ||||
|           parse_arg_id<ID>(str.data() + POS + 1, str.data() + str.size()); | ||||
|  | @ -364,28 +384,27 @@ constexpr auto compile_format_string(S format_str) { | |||
|       constexpr char_type c = | ||||
|           arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type(); | ||||
|       static_assert(c == '}' || c == ':', "missing '}' in format string"); | ||||
|       if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) { | ||||
|       if constexpr (arg_id_result.kind == arg_id_kind::index) { | ||||
|         static_assert( | ||||
|             ID == manual_indexing_id || ID == 0, | ||||
|             "cannot switch from automatic to manual argument indexing"); | ||||
|         constexpr auto arg_index = arg_id_result.arg_id.val.index; | ||||
|         constexpr auto arg_index = arg_id_result.arg_id.index; | ||||
|         return parse_replacement_field_then_tail<get_type<arg_index, Args>, | ||||
|                                                  Args, arg_id_end_pos, | ||||
|                                                  arg_index, manual_indexing_id>( | ||||
|             format_str); | ||||
|       } else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) { | ||||
|             fmt); | ||||
|       } else if constexpr (arg_id_result.kind == arg_id_kind::name) { | ||||
|         constexpr auto arg_index = | ||||
|             get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{}); | ||||
|             get_arg_index_by_name(arg_id_result.arg_id.name, Args{}); | ||||
|         if constexpr (arg_index >= 0) { | ||||
|           constexpr auto next_id = | ||||
|               ID != manual_indexing_id ? ID + 1 : manual_indexing_id; | ||||
|           return parse_replacement_field_then_tail< | ||||
|               decltype(get_type<arg_index, Args>::value), Args, arg_id_end_pos, | ||||
|               arg_index, next_id>(format_str); | ||||
|               arg_index, next_id>(fmt); | ||||
|         } else if constexpr (c == '}') { | ||||
|           return parse_tail<Args, arg_id_end_pos + 1, ID>( | ||||
|               runtime_named_field<char_type>{arg_id_result.arg_id.val.name}, | ||||
|               format_str); | ||||
|               runtime_named_field<char_type>{arg_id_result.arg_id.name}, fmt); | ||||
|         } else if constexpr (c == ':') { | ||||
|           return unknown_format();  // no type info for specs parsing
 | ||||
|         } | ||||
|  | @ -394,29 +413,26 @@ constexpr auto compile_format_string(S format_str) { | |||
|   } else if constexpr (str[POS] == '}') { | ||||
|     if constexpr (POS + 1 == str.size()) | ||||
|       FMT_THROW(format_error("unmatched '}' in format string")); | ||||
|     return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str); | ||||
|     return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), fmt); | ||||
|   } else { | ||||
|     constexpr auto end = parse_text(str, POS + 1); | ||||
|     if constexpr (end - POS > 1) { | ||||
|       return parse_tail<Args, end, ID>(make_text(str, POS, end - POS), | ||||
|                                        format_str); | ||||
|       return parse_tail<Args, end, ID>(make_text(str, POS, end - POS), fmt); | ||||
|     } else { | ||||
|       return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]}, | ||||
|                                        format_str); | ||||
|       return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]}, fmt); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| template <typename... Args, typename S, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| constexpr auto compile(S format_str) { | ||||
|   constexpr auto str = basic_string_view<typename S::char_type>(format_str); | ||||
| constexpr auto compile(S fmt) { | ||||
|   constexpr auto str = basic_string_view<typename S::char_type>(fmt); | ||||
|   if constexpr (str.size() == 0) { | ||||
|     return detail::make_text(str, 0, 0); | ||||
|   } else { | ||||
|     constexpr auto result = | ||||
|         detail::compile_format_string<detail::type_list<Args...>, 0, 0>( | ||||
|             format_str); | ||||
|         detail::compile_format_string<detail::type_list<Args...>, 0, 0>(fmt); | ||||
|     return result; | ||||
|   } | ||||
| } | ||||
|  | @ -488,39 +504,40 @@ FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) { | |||
| 
 | ||||
| template <typename OutputIt, typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n, | ||||
|                                          const S& format_str, Args&&... args) { | ||||
| auto format_to_n(OutputIt out, size_t n, const S& fmt, Args&&... args) | ||||
|     -> format_to_n_result<OutputIt> { | ||||
|   using traits = detail::fixed_buffer_traits; | ||||
|   auto buf = detail::iterator_buffer<OutputIt, char, traits>(out, n); | ||||
|   format_to(std::back_inserter(buf), format_str, std::forward<Args>(args)...); | ||||
|   fmt::format_to(std::back_inserter(buf), fmt, std::forward<Args>(args)...); | ||||
|   return {buf.out(), buf.count()}; | ||||
| } | ||||
| 
 | ||||
| template <typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| FMT_CONSTEXPR20 size_t formatted_size(const S& format_str, | ||||
|                                       const Args&... args) { | ||||
|   return fmt::format_to(detail::counting_iterator(), format_str, args...) | ||||
|       .count(); | ||||
| FMT_CONSTEXPR20 auto formatted_size(const S& fmt, const Args&... args) | ||||
|     -> size_t { | ||||
|   auto buf = detail::counting_buffer<>(); | ||||
|   fmt::format_to(appender(buf), fmt, args...); | ||||
|   return buf.count(); | ||||
| } | ||||
| 
 | ||||
| template <typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| void print(std::FILE* f, const S& format_str, const Args&... args) { | ||||
|   memory_buffer buffer; | ||||
|   fmt::format_to(std::back_inserter(buffer), format_str, args...); | ||||
|   detail::print(f, {buffer.data(), buffer.size()}); | ||||
| void print(std::FILE* f, const S& fmt, const Args&... args) { | ||||
|   auto buf = memory_buffer(); | ||||
|   fmt::format_to(appender(buf), fmt, args...); | ||||
|   detail::print(f, {buf.data(), buf.size()}); | ||||
| } | ||||
| 
 | ||||
| template <typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| void print(const S& format_str, const Args&... args) { | ||||
|   print(stdout, format_str, args...); | ||||
| void print(const S& fmt, const Args&... args) { | ||||
|   print(stdout, fmt, args...); | ||||
| } | ||||
| 
 | ||||
| #if FMT_USE_NONTYPE_TEMPLATE_ARGS | ||||
| inline namespace literals { | ||||
| template <detail_exported::fixed_string Str> constexpr auto operator""_cf() { | ||||
| template <detail::fixed_string Str> constexpr auto operator""_cf() { | ||||
|   using char_t = remove_cvref_t<decltype(Str.data[0])>; | ||||
|   return detail::udl_compiled_string<char_t, sizeof(Str.data) / sizeof(char_t), | ||||
|                                      Str>(); | ||||
|  |  | |||
							
								
								
									
										2925
									
								
								thirdparty/fmt/include/fmt/core.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2925
									
								
								thirdparty/fmt/include/fmt/core.h
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										533
									
								
								thirdparty/fmt/include/fmt/format-inl.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										533
									
								
								thirdparty/fmt/include/fmt/format-inl.h
									
										
									
									
										vendored
									
									
								
							|  | @ -8,36 +8,36 @@ | |||
| #ifndef FMT_FORMAT_INL_H_ | ||||
| #define FMT_FORMAT_INL_H_ | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <cerrno>  // errno | ||||
| #include <climits> | ||||
| #include <cmath> | ||||
| #include <exception> | ||||
| 
 | ||||
| #ifndef FMT_STATIC_THOUSANDS_SEPARATOR | ||||
| #  include <locale> | ||||
| #ifndef FMT_MODULE | ||||
| #  include <algorithm> | ||||
| #  include <cerrno>  // errno
 | ||||
| #  include <climits> | ||||
| #  include <cmath> | ||||
| #  include <exception> | ||||
| #endif | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| #if defined(_WIN32) && !defined(FMT_USE_WRITE_CONSOLE) | ||||
| #  include <io.h>  // _isatty
 | ||||
| #endif | ||||
| 
 | ||||
| #include "format.h" | ||||
| 
 | ||||
| #if FMT_USE_LOCALE | ||||
| #  include <locale> | ||||
| #endif | ||||
| 
 | ||||
| #ifndef FMT_FUNC | ||||
| #  define FMT_FUNC | ||||
| #endif | ||||
| 
 | ||||
| FMT_BEGIN_NAMESPACE | ||||
| namespace detail { | ||||
| 
 | ||||
| FMT_FUNC void assert_fail(const char* file, int line, const char* message) { | ||||
|   // Use unchecked std::fprintf to avoid triggering another assertion when
 | ||||
|   // writing to stderr fails
 | ||||
|   std::fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message); | ||||
|   // Chosen instead of std::abort to satisfy Clang in CUDA mode during device
 | ||||
|   // code pass.
 | ||||
|   std::terminate(); | ||||
| } | ||||
| 
 | ||||
| FMT_FUNC void throw_format_error(const char* message) { | ||||
|   FMT_THROW(format_error(message)); | ||||
|   // writing to stderr fails.
 | ||||
|   fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message); | ||||
|   abort(); | ||||
| } | ||||
| 
 | ||||
| FMT_FUNC void format_error_code(detail::buffer<char>& out, int error_code, | ||||
|  | @ -56,112 +56,127 @@ FMT_FUNC void format_error_code(detail::buffer<char>& out, int error_code, | |||
|     ++error_code_size; | ||||
|   } | ||||
|   error_code_size += detail::to_unsigned(detail::count_digits(abs_value)); | ||||
|   auto it = buffer_appender<char>(out); | ||||
|   auto it = appender(out); | ||||
|   if (message.size() <= inline_buffer_size - error_code_size) | ||||
|     format_to(it, FMT_STRING("{}{}"), message, SEP); | ||||
|   format_to(it, FMT_STRING("{}{}"), ERROR_STR, error_code); | ||||
|     fmt::format_to(it, FMT_STRING("{}{}"), message, SEP); | ||||
|   fmt::format_to(it, FMT_STRING("{}{}"), ERROR_STR, error_code); | ||||
|   FMT_ASSERT(out.size() <= inline_buffer_size, ""); | ||||
| } | ||||
| 
 | ||||
| FMT_FUNC void report_error(format_func func, int error_code, | ||||
|                            const char* message) noexcept { | ||||
| FMT_FUNC void do_report_error(format_func func, int error_code, | ||||
|                               const char* message) noexcept { | ||||
|   memory_buffer full_message; | ||||
|   func(full_message, error_code, message); | ||||
|   // Don't use fwrite_fully because the latter may throw.
 | ||||
|   // Don't use fwrite_all because the latter may throw.
 | ||||
|   if (std::fwrite(full_message.data(), full_message.size(), 1, stderr) > 0) | ||||
|     std::fputc('\n', stderr); | ||||
| } | ||||
| 
 | ||||
| // A wrapper around fwrite that throws on error.
 | ||||
| inline void fwrite_fully(const void* ptr, size_t size, size_t count, | ||||
|                          FILE* stream) { | ||||
|   size_t written = std::fwrite(ptr, size, count, stream); | ||||
| inline void fwrite_all(const void* ptr, size_t count, FILE* stream) { | ||||
|   size_t written = std::fwrite(ptr, 1, count, stream); | ||||
|   if (written < count) | ||||
|     FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); | ||||
| } | ||||
| 
 | ||||
| #ifndef FMT_STATIC_THOUSANDS_SEPARATOR | ||||
| template <typename Locale> | ||||
| locale_ref::locale_ref(const Locale& loc) : locale_(&loc) { | ||||
|   static_assert(std::is_same<Locale, std::locale>::value, ""); | ||||
| } | ||||
| #if FMT_USE_LOCALE | ||||
| using std::locale; | ||||
| using std::numpunct; | ||||
| using std::use_facet; | ||||
| 
 | ||||
| template <typename Locale> Locale locale_ref::get() const { | ||||
|   static_assert(std::is_same<Locale, std::locale>::value, ""); | ||||
|   return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale(); | ||||
| template <typename Locale, enable_if_t<(sizeof(Locale::collate) != 0), int>> | ||||
| locale_ref::locale_ref(const Locale& loc) : locale_(&loc) { | ||||
|   static_assert(std::is_same<Locale, locale>::value, ""); | ||||
| } | ||||
| #else | ||||
| struct locale {}; | ||||
| template <typename Char> struct numpunct { | ||||
|   auto grouping() const -> std::string { return "\03"; } | ||||
|   auto thousands_sep() const -> Char { return ','; } | ||||
|   auto decimal_point() const -> Char { return '.'; } | ||||
| }; | ||||
| template <typename Facet> Facet use_facet(locale) { return {}; } | ||||
| #endif  // FMT_USE_LOCALE
 | ||||
| 
 | ||||
| template <typename Locale> auto locale_ref::get() const -> Locale { | ||||
|   static_assert(std::is_same<Locale, locale>::value, ""); | ||||
| #if FMT_USE_LOCALE | ||||
|   if (locale_) return *static_cast<const locale*>(locale_); | ||||
| #endif | ||||
|   return locale(); | ||||
| } | ||||
| 
 | ||||
| template <typename Char> | ||||
| FMT_FUNC auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result<Char> { | ||||
|   auto& facet = std::use_facet<std::numpunct<Char>>(loc.get<std::locale>()); | ||||
|   auto&& facet = use_facet<numpunct<Char>>(loc.get<locale>()); | ||||
|   auto grouping = facet.grouping(); | ||||
|   auto thousands_sep = grouping.empty() ? Char() : facet.thousands_sep(); | ||||
|   return {std::move(grouping), thousands_sep}; | ||||
| } | ||||
| template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref loc) { | ||||
|   return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>()) | ||||
|       .decimal_point(); | ||||
| } | ||||
| #else | ||||
| template <typename Char> | ||||
| FMT_FUNC auto thousands_sep_impl(locale_ref) -> thousands_sep_result<Char> { | ||||
|   return {"\03", FMT_STATIC_THOUSANDS_SEPARATOR}; | ||||
| FMT_FUNC auto decimal_point_impl(locale_ref loc) -> Char { | ||||
|   return use_facet<numpunct<Char>>(loc.get<locale>()).decimal_point(); | ||||
| } | ||||
| template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref) { | ||||
|   return '.'; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #if FMT_USE_LOCALE | ||||
| FMT_FUNC auto write_loc(appender out, loc_value value, | ||||
|                         const format_specs<>& specs, locale_ref loc) -> bool { | ||||
| #ifndef FMT_STATIC_THOUSANDS_SEPARATOR | ||||
|                         const format_specs& specs, locale_ref loc) -> bool { | ||||
|   auto locale = loc.get<std::locale>(); | ||||
|   // We cannot use the num_put<char> facet because it may produce output in
 | ||||
|   // a wrong encoding.
 | ||||
|   using facet = format_facet<std::locale>; | ||||
|   if (std::has_facet<facet>(locale)) | ||||
|     return std::use_facet<facet>(locale).put(out, value, specs); | ||||
|     return use_facet<facet>(locale).put(out, value, specs); | ||||
|   return facet(locale).put(out, value, specs); | ||||
| #endif | ||||
|   return false; | ||||
| } | ||||
| #endif | ||||
| }  // namespace detail
 | ||||
| 
 | ||||
| FMT_FUNC void report_error(const char* message) { | ||||
| #if FMT_USE_EXCEPTIONS | ||||
|   throw format_error(message); | ||||
| #else | ||||
|   fputs(message, stderr); | ||||
|   abort(); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| template <typename Locale> typename Locale::id format_facet<Locale>::id; | ||||
| 
 | ||||
| #ifndef FMT_STATIC_THOUSANDS_SEPARATOR | ||||
| template <typename Locale> format_facet<Locale>::format_facet(Locale& loc) { | ||||
|   auto& numpunct = std::use_facet<std::numpunct<char>>(loc); | ||||
|   grouping_ = numpunct.grouping(); | ||||
|   if (!grouping_.empty()) separator_ = std::string(1, numpunct.thousands_sep()); | ||||
|   auto& np = detail::use_facet<detail::numpunct<char>>(loc); | ||||
|   grouping_ = np.grouping(); | ||||
|   if (!grouping_.empty()) separator_ = std::string(1, np.thousands_sep()); | ||||
| } | ||||
| 
 | ||||
| #if FMT_USE_LOCALE | ||||
| template <> | ||||
| FMT_API FMT_FUNC auto format_facet<std::locale>::do_put( | ||||
|     appender out, loc_value val, const format_specs<>& specs) const -> bool { | ||||
|     appender out, loc_value val, const format_specs& specs) const -> bool { | ||||
|   return val.visit( | ||||
|       detail::loc_writer<>{out, specs, separator_, grouping_, decimal_point_}); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| FMT_FUNC std::system_error vsystem_error(int error_code, string_view fmt, | ||||
|                                          format_args args) { | ||||
| FMT_FUNC auto vsystem_error(int error_code, string_view fmt, format_args args) | ||||
|     -> std::system_error { | ||||
|   auto ec = std::error_code(error_code, std::generic_category()); | ||||
|   return std::system_error(ec, vformat(fmt, args)); | ||||
| } | ||||
| 
 | ||||
| namespace detail { | ||||
| 
 | ||||
| template <typename F> inline bool operator==(basic_fp<F> x, basic_fp<F> y) { | ||||
| template <typename F> | ||||
| inline auto operator==(basic_fp<F> x, basic_fp<F> y) -> bool { | ||||
|   return x.f == y.f && x.e == y.e; | ||||
| } | ||||
| 
 | ||||
| // Compilers should be able to optimize this into the ror instruction.
 | ||||
| FMT_CONSTEXPR inline uint32_t rotr(uint32_t n, uint32_t r) noexcept { | ||||
| FMT_CONSTEXPR inline auto rotr(uint32_t n, uint32_t r) noexcept -> uint32_t { | ||||
|   r &= 31; | ||||
|   return (n >> r) | (n << (32 - r)); | ||||
| } | ||||
| FMT_CONSTEXPR inline uint64_t rotr(uint64_t n, uint32_t r) noexcept { | ||||
| FMT_CONSTEXPR inline auto rotr(uint64_t n, uint32_t r) noexcept -> uint64_t { | ||||
|   r &= 63; | ||||
|   return (n >> r) | (n << (64 - r)); | ||||
| } | ||||
|  | @ -170,14 +185,14 @@ FMT_CONSTEXPR inline uint64_t rotr(uint64_t n, uint32_t r) noexcept { | |||
| namespace dragonbox { | ||||
| // Computes upper 64 bits of multiplication of a 32-bit unsigned integer and a
 | ||||
| // 64-bit unsigned integer.
 | ||||
| inline uint64_t umul96_upper64(uint32_t x, uint64_t y) noexcept { | ||||
| inline auto umul96_upper64(uint32_t x, uint64_t y) noexcept -> uint64_t { | ||||
|   return umul128_upper64(static_cast<uint64_t>(x) << 32, y); | ||||
| } | ||||
| 
 | ||||
| // Computes lower 128 bits of multiplication of a 64-bit unsigned integer and a
 | ||||
| // 128-bit unsigned integer.
 | ||||
| inline uint128_fallback umul192_lower128(uint64_t x, | ||||
|                                          uint128_fallback y) noexcept { | ||||
| inline auto umul192_lower128(uint64_t x, uint128_fallback y) noexcept | ||||
|     -> uint128_fallback { | ||||
|   uint64_t high = x * y.high(); | ||||
|   uint128_fallback high_low = umul128(x, y.low()); | ||||
|   return {high + high_low.high(), high_low.low()}; | ||||
|  | @ -185,12 +200,12 @@ inline uint128_fallback umul192_lower128(uint64_t x, | |||
| 
 | ||||
| // Computes lower 64 bits of multiplication of a 32-bit unsigned integer and a
 | ||||
| // 64-bit unsigned integer.
 | ||||
| inline uint64_t umul96_lower64(uint32_t x, uint64_t y) noexcept { | ||||
| inline auto umul96_lower64(uint32_t x, uint64_t y) noexcept -> uint64_t { | ||||
|   return x * y; | ||||
| } | ||||
| 
 | ||||
| // Various fast log computations.
 | ||||
| inline int floor_log10_pow2_minus_log10_4_over_3(int e) noexcept { | ||||
| inline auto floor_log10_pow2_minus_log10_4_over_3(int e) noexcept -> int { | ||||
|   FMT_ASSERT(e <= 2936 && e >= -2985, "too large exponent"); | ||||
|   return (e * 631305 - 261663) >> 21; | ||||
| } | ||||
|  | @ -204,7 +219,7 @@ FMT_INLINE_VARIABLE constexpr struct { | |||
| // divisible by pow(10, N).
 | ||||
| // Precondition: n <= pow(10, N + 1).
 | ||||
| template <int N> | ||||
| bool check_divisibility_and_divide_by_pow10(uint32_t& n) noexcept { | ||||
| auto check_divisibility_and_divide_by_pow10(uint32_t& n) noexcept -> bool { | ||||
|   // The numbers below are chosen such that:
 | ||||
|   //   1. floor(n/d) = floor(nm / 2^k) where d=10 or d=100,
 | ||||
|   //   2. nm mod 2^k < m if and only if n is divisible by d,
 | ||||
|  | @ -229,7 +244,7 @@ bool check_divisibility_and_divide_by_pow10(uint32_t& n) noexcept { | |||
| 
 | ||||
| // Computes floor(n / pow(10, N)) for small n and N.
 | ||||
| // Precondition: n <= pow(10, N + 1).
 | ||||
| template <int N> uint32_t small_division_by_pow10(uint32_t n) noexcept { | ||||
| template <int N> auto small_division_by_pow10(uint32_t n) noexcept -> uint32_t { | ||||
|   constexpr auto info = div_small_pow10_infos[N - 1]; | ||||
|   FMT_ASSERT(n <= info.divisor * 10, "n is too large"); | ||||
|   constexpr uint32_t magic_number = | ||||
|  | @ -238,12 +253,12 @@ template <int N> uint32_t small_division_by_pow10(uint32_t n) noexcept { | |||
| } | ||||
| 
 | ||||
| // Computes floor(n / 10^(kappa + 1)) (float)
 | ||||
| inline uint32_t divide_by_10_to_kappa_plus_1(uint32_t n) noexcept { | ||||
| inline auto divide_by_10_to_kappa_plus_1(uint32_t n) noexcept -> uint32_t { | ||||
|   // 1374389535 = ceil(2^37/100)
 | ||||
|   return static_cast<uint32_t>((static_cast<uint64_t>(n) * 1374389535) >> 37); | ||||
| } | ||||
| // Computes floor(n / 10^(kappa + 1)) (double)
 | ||||
| inline uint64_t divide_by_10_to_kappa_plus_1(uint64_t n) noexcept { | ||||
| inline auto divide_by_10_to_kappa_plus_1(uint64_t n) noexcept -> uint64_t { | ||||
|   // 2361183241434822607 = ceil(2^(64+7)/1000)
 | ||||
|   return umul128_upper64(n, 2361183241434822607ull) >> 7; | ||||
| } | ||||
|  | @ -255,7 +270,7 @@ template <> struct cache_accessor<float> { | |||
|   using carrier_uint = float_info<float>::carrier_uint; | ||||
|   using cache_entry_type = uint64_t; | ||||
| 
 | ||||
|   static uint64_t get_cached_power(int k) noexcept { | ||||
|   static auto get_cached_power(int k) noexcept -> uint64_t { | ||||
|     FMT_ASSERT(k >= float_info<float>::min_k && k <= float_info<float>::max_k, | ||||
|                "k is out of range"); | ||||
|     static constexpr const uint64_t pow10_significands[] = { | ||||
|  | @ -297,20 +312,23 @@ template <> struct cache_accessor<float> { | |||
|     bool is_integer; | ||||
|   }; | ||||
| 
 | ||||
|   static compute_mul_result compute_mul( | ||||
|       carrier_uint u, const cache_entry_type& cache) noexcept { | ||||
|   static auto compute_mul(carrier_uint u, | ||||
|                           const cache_entry_type& cache) noexcept | ||||
|       -> compute_mul_result { | ||||
|     auto r = umul96_upper64(u, cache); | ||||
|     return {static_cast<carrier_uint>(r >> 32), | ||||
|             static_cast<carrier_uint>(r) == 0}; | ||||
|   } | ||||
| 
 | ||||
|   static uint32_t compute_delta(const cache_entry_type& cache, | ||||
|                                 int beta) noexcept { | ||||
|   static auto compute_delta(const cache_entry_type& cache, int beta) noexcept | ||||
|       -> uint32_t { | ||||
|     return static_cast<uint32_t>(cache >> (64 - 1 - beta)); | ||||
|   } | ||||
| 
 | ||||
|   static compute_mul_parity_result compute_mul_parity( | ||||
|       carrier_uint two_f, const cache_entry_type& cache, int beta) noexcept { | ||||
|   static auto compute_mul_parity(carrier_uint two_f, | ||||
|                                  const cache_entry_type& cache, | ||||
|                                  int beta) noexcept | ||||
|       -> compute_mul_parity_result { | ||||
|     FMT_ASSERT(beta >= 1, ""); | ||||
|     FMT_ASSERT(beta < 64, ""); | ||||
| 
 | ||||
|  | @ -319,22 +337,22 @@ template <> struct cache_accessor<float> { | |||
|             static_cast<uint32_t>(r >> (32 - beta)) == 0}; | ||||
|   } | ||||
| 
 | ||||
|   static carrier_uint compute_left_endpoint_for_shorter_interval_case( | ||||
|       const cache_entry_type& cache, int beta) noexcept { | ||||
|   static auto compute_left_endpoint_for_shorter_interval_case( | ||||
|       const cache_entry_type& cache, int beta) noexcept -> carrier_uint { | ||||
|     return static_cast<carrier_uint>( | ||||
|         (cache - (cache >> (num_significand_bits<float>() + 2))) >> | ||||
|         (64 - num_significand_bits<float>() - 1 - beta)); | ||||
|   } | ||||
| 
 | ||||
|   static carrier_uint compute_right_endpoint_for_shorter_interval_case( | ||||
|       const cache_entry_type& cache, int beta) noexcept { | ||||
|   static auto compute_right_endpoint_for_shorter_interval_case( | ||||
|       const cache_entry_type& cache, int beta) noexcept -> carrier_uint { | ||||
|     return static_cast<carrier_uint>( | ||||
|         (cache + (cache >> (num_significand_bits<float>() + 1))) >> | ||||
|         (64 - num_significand_bits<float>() - 1 - beta)); | ||||
|   } | ||||
| 
 | ||||
|   static carrier_uint compute_round_up_for_shorter_interval_case( | ||||
|       const cache_entry_type& cache, int beta) noexcept { | ||||
|   static auto compute_round_up_for_shorter_interval_case( | ||||
|       const cache_entry_type& cache, int beta) noexcept -> carrier_uint { | ||||
|     return (static_cast<carrier_uint>( | ||||
|                 cache >> (64 - num_significand_bits<float>() - 2 - beta)) + | ||||
|             1) / | ||||
|  | @ -346,7 +364,7 @@ template <> struct cache_accessor<double> { | |||
|   using carrier_uint = float_info<double>::carrier_uint; | ||||
|   using cache_entry_type = uint128_fallback; | ||||
| 
 | ||||
|   static uint128_fallback get_cached_power(int k) noexcept { | ||||
|   static auto get_cached_power(int k) noexcept -> uint128_fallback { | ||||
|     FMT_ASSERT(k >= float_info<double>::min_k && k <= float_info<double>::max_k, | ||||
|                "k is out of range"); | ||||
| 
 | ||||
|  | @ -985,8 +1003,7 @@ template <> struct cache_accessor<double> { | |||
|       {0xe0accfa875af45a7, 0x93eb1b80a33b8606}, | ||||
|       {0x8c6c01c9498d8b88, 0xbc72f130660533c4}, | ||||
|       {0xaf87023b9bf0ee6a, 0xeb8fad7c7f8680b5}, | ||||
|       { 0xdb68c2ca82ed2a05, | ||||
|         0xa67398db9f6820e2 } | ||||
|       {0xdb68c2ca82ed2a05, 0xa67398db9f6820e2}, | ||||
| #else | ||||
|       {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, | ||||
|       {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, | ||||
|  | @ -1071,19 +1088,22 @@ template <> struct cache_accessor<double> { | |||
|     bool is_integer; | ||||
|   }; | ||||
| 
 | ||||
|   static compute_mul_result compute_mul( | ||||
|       carrier_uint u, const cache_entry_type& cache) noexcept { | ||||
|   static auto compute_mul(carrier_uint u, | ||||
|                           const cache_entry_type& cache) noexcept | ||||
|       -> compute_mul_result { | ||||
|     auto r = umul192_upper128(u, cache); | ||||
|     return {r.high(), r.low() == 0}; | ||||
|   } | ||||
| 
 | ||||
|   static uint32_t compute_delta(cache_entry_type const& cache, | ||||
|                                 int beta) noexcept { | ||||
|   static auto compute_delta(cache_entry_type const& cache, int beta) noexcept | ||||
|       -> uint32_t { | ||||
|     return static_cast<uint32_t>(cache.high() >> (64 - 1 - beta)); | ||||
|   } | ||||
| 
 | ||||
|   static compute_mul_parity_result compute_mul_parity( | ||||
|       carrier_uint two_f, const cache_entry_type& cache, int beta) noexcept { | ||||
|   static auto compute_mul_parity(carrier_uint two_f, | ||||
|                                  const cache_entry_type& cache, | ||||
|                                  int beta) noexcept | ||||
|       -> compute_mul_parity_result { | ||||
|     FMT_ASSERT(beta >= 1, ""); | ||||
|     FMT_ASSERT(beta < 64, ""); | ||||
| 
 | ||||
|  | @ -1092,35 +1112,35 @@ template <> struct cache_accessor<double> { | |||
|             ((r.high() << beta) | (r.low() >> (64 - beta))) == 0}; | ||||
|   } | ||||
| 
 | ||||
|   static carrier_uint compute_left_endpoint_for_shorter_interval_case( | ||||
|       const cache_entry_type& cache, int beta) noexcept { | ||||
|   static auto compute_left_endpoint_for_shorter_interval_case( | ||||
|       const cache_entry_type& cache, int beta) noexcept -> carrier_uint { | ||||
|     return (cache.high() - | ||||
|             (cache.high() >> (num_significand_bits<double>() + 2))) >> | ||||
|            (64 - num_significand_bits<double>() - 1 - beta); | ||||
|   } | ||||
| 
 | ||||
|   static carrier_uint compute_right_endpoint_for_shorter_interval_case( | ||||
|       const cache_entry_type& cache, int beta) noexcept { | ||||
|   static auto compute_right_endpoint_for_shorter_interval_case( | ||||
|       const cache_entry_type& cache, int beta) noexcept -> carrier_uint { | ||||
|     return (cache.high() + | ||||
|             (cache.high() >> (num_significand_bits<double>() + 1))) >> | ||||
|            (64 - num_significand_bits<double>() - 1 - beta); | ||||
|   } | ||||
| 
 | ||||
|   static carrier_uint compute_round_up_for_shorter_interval_case( | ||||
|       const cache_entry_type& cache, int beta) noexcept { | ||||
|   static auto compute_round_up_for_shorter_interval_case( | ||||
|       const cache_entry_type& cache, int beta) noexcept -> carrier_uint { | ||||
|     return ((cache.high() >> (64 - num_significand_bits<double>() - 2 - beta)) + | ||||
|             1) / | ||||
|            2; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| FMT_FUNC uint128_fallback get_cached_power(int k) noexcept { | ||||
| FMT_FUNC auto get_cached_power(int k) noexcept -> uint128_fallback { | ||||
|   return cache_accessor<double>::get_cached_power(k); | ||||
| } | ||||
| 
 | ||||
| // Various integer checks
 | ||||
| template <typename T> | ||||
| bool is_left_endpoint_integer_shorter_interval(int exponent) noexcept { | ||||
| auto is_left_endpoint_integer_shorter_interval(int exponent) noexcept -> bool { | ||||
|   const int case_shorter_interval_left_endpoint_lower_threshold = 2; | ||||
|   const int case_shorter_interval_left_endpoint_upper_threshold = 3; | ||||
|   return exponent >= case_shorter_interval_left_endpoint_lower_threshold && | ||||
|  | @ -1132,7 +1152,7 @@ FMT_INLINE int remove_trailing_zeros(uint32_t& n, int s = 0) noexcept { | |||
|   FMT_ASSERT(n != 0, ""); | ||||
|   // Modular inverse of 5 (mod 2^32): (mod_inv_5 * 5) mod 2^32 = 1.
 | ||||
|   constexpr uint32_t mod_inv_5 = 0xcccccccd; | ||||
|   constexpr uint32_t mod_inv_25 = 0xc28f5c29; // = mod_inv_5 * mod_inv_5
 | ||||
|   constexpr uint32_t mod_inv_25 = 0xc28f5c29;  // = mod_inv_5 * mod_inv_5
 | ||||
| 
 | ||||
|   while (true) { | ||||
|     auto q = rotr(n * mod_inv_25, 2); | ||||
|  | @ -1168,7 +1188,7 @@ FMT_INLINE int remove_trailing_zeros(uint64_t& n) noexcept { | |||
| 
 | ||||
|   // If n is not divisible by 10^8, work with n itself.
 | ||||
|   constexpr uint64_t mod_inv_5 = 0xcccccccccccccccd; | ||||
|   constexpr uint64_t mod_inv_25 = 0x8f5c28f5c28f5c29; // = mod_inv_5 * mod_inv_5
 | ||||
|   constexpr uint64_t mod_inv_25 = 0x8f5c28f5c28f5c29;  // mod_inv_5 * mod_inv_5
 | ||||
| 
 | ||||
|   int s = 0; | ||||
|   while (true) { | ||||
|  | @ -1234,7 +1254,7 @@ FMT_INLINE decimal_fp<T> shorter_interval_case(int exponent) noexcept { | |||
|   return ret_value; | ||||
| } | ||||
| 
 | ||||
| template <typename T> decimal_fp<T> to_decimal(T x) noexcept { | ||||
| template <typename T> auto to_decimal(T x) noexcept -> decimal_fp<T> { | ||||
|   // Step 1: integer promotion & Schubfach multiplier calculation.
 | ||||
| 
 | ||||
|   using carrier_uint = typename float_info<T>::carrier_uint; | ||||
|  | @ -1373,15 +1393,15 @@ template <> struct formatter<detail::bigint> { | |||
|     for (auto i = n.bigits_.size(); i > 0; --i) { | ||||
|       auto value = n.bigits_[i - 1u]; | ||||
|       if (first) { | ||||
|         out = format_to(out, FMT_STRING("{:x}"), value); | ||||
|         out = fmt::format_to(out, FMT_STRING("{:x}"), value); | ||||
|         first = false; | ||||
|         continue; | ||||
|       } | ||||
|       out = format_to(out, FMT_STRING("{:08x}"), value); | ||||
|       out = fmt::format_to(out, FMT_STRING("{:08x}"), value); | ||||
|     } | ||||
|     if (n.exp_ > 0) | ||||
|       out = format_to(out, FMT_STRING("p{}"), | ||||
|                       n.exp_ * detail::bigint::bigit_bits); | ||||
|       out = fmt::format_to(out, FMT_STRING("p{}"), | ||||
|                            n.exp_ * detail::bigint::bigit_bits); | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
|  | @ -1405,7 +1425,7 @@ FMT_FUNC void format_system_error(detail::buffer<char>& out, int error_code, | |||
|                                   const char* message) noexcept { | ||||
|   FMT_TRY { | ||||
|     auto ec = std::error_code(error_code, std::generic_category()); | ||||
|     write(std::back_inserter(out), std::system_error(ec, message).what()); | ||||
|     detail::write(appender(out), std::system_error(ec, message).what()); | ||||
|     return; | ||||
|   } | ||||
|   FMT_CATCH(...) {} | ||||
|  | @ -1414,10 +1434,10 @@ FMT_FUNC void format_system_error(detail::buffer<char>& out, int error_code, | |||
| 
 | ||||
| FMT_FUNC void report_system_error(int error_code, | ||||
|                                   const char* message) noexcept { | ||||
|   report_error(format_system_error, error_code, message); | ||||
|   do_report_error(format_system_error, error_code, message); | ||||
| } | ||||
| 
 | ||||
| FMT_FUNC std::string vformat(string_view fmt, format_args args) { | ||||
| FMT_FUNC auto vformat(string_view fmt, format_args args) -> std::string { | ||||
|   // Don't optimize the "{}" case to keep the binary size small and because it
 | ||||
|   // can be better optimized in fmt::format anyway.
 | ||||
|   auto buffer = memory_buffer(); | ||||
|  | @ -1426,42 +1446,307 @@ FMT_FUNC std::string vformat(string_view fmt, format_args args) { | |||
| } | ||||
| 
 | ||||
| namespace detail { | ||||
| #ifndef _WIN32 | ||||
| FMT_FUNC bool write_console(std::FILE*, string_view) { return false; } | ||||
| 
 | ||||
| FMT_FUNC void vformat_to(buffer<char>& buf, string_view fmt, format_args args, | ||||
|                          locale_ref loc) { | ||||
|   auto out = appender(buf); | ||||
|   if (fmt.size() == 2 && equal2(fmt.data(), "{}")) | ||||
|     return args.get(0).visit(default_arg_formatter<char>{out}); | ||||
|   parse_format_string( | ||||
|       fmt, format_handler<char>{parse_context<char>(fmt), {out, args, loc}}); | ||||
| } | ||||
| 
 | ||||
| template <typename T> struct span { | ||||
|   T* data; | ||||
|   size_t size; | ||||
| }; | ||||
| 
 | ||||
| template <typename F> auto flockfile(F* f) -> decltype(_lock_file(f)) { | ||||
|   _lock_file(f); | ||||
| } | ||||
| template <typename F> auto funlockfile(F* f) -> decltype(_unlock_file(f)) { | ||||
|   _unlock_file(f); | ||||
| } | ||||
| 
 | ||||
| #ifndef getc_unlocked | ||||
| template <typename F> auto getc_unlocked(F* f) -> decltype(_fgetc_nolock(f)) { | ||||
|   return _fgetc_nolock(f); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| template <typename F = FILE, typename Enable = void> | ||||
| struct has_flockfile : std::false_type {}; | ||||
| 
 | ||||
| template <typename F> | ||||
| struct has_flockfile<F, void_t<decltype(flockfile(&std::declval<F&>()))>> | ||||
|     : std::true_type {}; | ||||
| 
 | ||||
| // A FILE wrapper. F is FILE defined as a template parameter to make system API
 | ||||
| // detection work.
 | ||||
| template <typename F> class file_base { | ||||
|  public: | ||||
|   F* file_; | ||||
| 
 | ||||
|  public: | ||||
|   file_base(F* file) : file_(file) {} | ||||
|   operator F*() const { return file_; } | ||||
| 
 | ||||
|   // Reads a code unit from the stream.
 | ||||
|   auto get() -> int { | ||||
|     int result = getc_unlocked(file_); | ||||
|     if (result == EOF && ferror(file_) != 0) | ||||
|       FMT_THROW(system_error(errno, FMT_STRING("getc failed"))); | ||||
|     return result; | ||||
|   } | ||||
| 
 | ||||
|   // Puts the code unit back into the stream buffer.
 | ||||
|   void unget(char c) { | ||||
|     if (ungetc(c, file_) == EOF) | ||||
|       FMT_THROW(system_error(errno, FMT_STRING("ungetc failed"))); | ||||
|   } | ||||
| 
 | ||||
|   void flush() { fflush(this->file_); } | ||||
| }; | ||||
| 
 | ||||
| // A FILE wrapper for glibc.
 | ||||
| template <typename F> class glibc_file : public file_base<F> { | ||||
|  private: | ||||
|   enum { | ||||
|     line_buffered = 0x200,  // _IO_LINE_BUF
 | ||||
|     unbuffered = 2          // _IO_UNBUFFERED
 | ||||
|   }; | ||||
| 
 | ||||
|  public: | ||||
|   using file_base<F>::file_base; | ||||
| 
 | ||||
|   auto is_buffered() const -> bool { | ||||
|     return (this->file_->_flags & unbuffered) == 0; | ||||
|   } | ||||
| 
 | ||||
|   void init_buffer() { | ||||
|     if (this->file_->_IO_write_ptr) return; | ||||
|     // Force buffer initialization by placing and removing a char in a buffer.
 | ||||
|     assume(this->file_->_IO_write_ptr >= this->file_->_IO_write_end); | ||||
|     putc_unlocked(0, this->file_); | ||||
|     --this->file_->_IO_write_ptr; | ||||
|   } | ||||
| 
 | ||||
|   // Returns the file's read buffer.
 | ||||
|   auto get_read_buffer() const -> span<const char> { | ||||
|     auto ptr = this->file_->_IO_read_ptr; | ||||
|     return {ptr, to_unsigned(this->file_->_IO_read_end - ptr)}; | ||||
|   } | ||||
| 
 | ||||
|   // Returns the file's write buffer.
 | ||||
|   auto get_write_buffer() const -> span<char> { | ||||
|     auto ptr = this->file_->_IO_write_ptr; | ||||
|     return {ptr, to_unsigned(this->file_->_IO_buf_end - ptr)}; | ||||
|   } | ||||
| 
 | ||||
|   void advance_write_buffer(size_t size) { this->file_->_IO_write_ptr += size; } | ||||
| 
 | ||||
|   bool needs_flush() const { | ||||
|     if ((this->file_->_flags & line_buffered) == 0) return false; | ||||
|     char* end = this->file_->_IO_write_end; | ||||
|     return memchr(end, '\n', to_unsigned(this->file_->_IO_write_ptr - end)); | ||||
|   } | ||||
| 
 | ||||
|   void flush() { fflush_unlocked(this->file_); } | ||||
| }; | ||||
| 
 | ||||
| // A FILE wrapper for Apple's libc.
 | ||||
| template <typename F> class apple_file : public file_base<F> { | ||||
|  private: | ||||
|   enum { | ||||
|     line_buffered = 1,  // __SNBF
 | ||||
|     unbuffered = 2      // __SLBF
 | ||||
|   }; | ||||
| 
 | ||||
|  public: | ||||
|   using file_base<F>::file_base; | ||||
| 
 | ||||
|   auto is_buffered() const -> bool { | ||||
|     return (this->file_->_flags & unbuffered) == 0; | ||||
|   } | ||||
| 
 | ||||
|   void init_buffer() { | ||||
|     if (this->file_->_p) return; | ||||
|     // Force buffer initialization by placing and removing a char in a buffer.
 | ||||
|     putc_unlocked(0, this->file_); | ||||
|     --this->file_->_p; | ||||
|     ++this->file_->_w; | ||||
|   } | ||||
| 
 | ||||
|   auto get_read_buffer() const -> span<const char> { | ||||
|     return {reinterpret_cast<char*>(this->file_->_p), | ||||
|             to_unsigned(this->file_->_r)}; | ||||
|   } | ||||
| 
 | ||||
|   auto get_write_buffer() const -> span<char> { | ||||
|     return {reinterpret_cast<char*>(this->file_->_p), | ||||
|             to_unsigned(this->file_->_bf._base + this->file_->_bf._size - | ||||
|                         this->file_->_p)}; | ||||
|   } | ||||
| 
 | ||||
|   void advance_write_buffer(size_t size) { | ||||
|     this->file_->_p += size; | ||||
|     this->file_->_w -= size; | ||||
|   } | ||||
| 
 | ||||
|   bool needs_flush() const { | ||||
|     if ((this->file_->_flags & line_buffered) == 0) return false; | ||||
|     return memchr(this->file_->_p + this->file_->_w, '\n', | ||||
|                   to_unsigned(-this->file_->_w)); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| // A fallback FILE wrapper.
 | ||||
| template <typename F> class fallback_file : public file_base<F> { | ||||
|  private: | ||||
|   char next_;  // The next unconsumed character in the buffer.
 | ||||
|   bool has_next_ = false; | ||||
| 
 | ||||
|  public: | ||||
|   using file_base<F>::file_base; | ||||
| 
 | ||||
|   auto is_buffered() const -> bool { return false; } | ||||
|   auto needs_flush() const -> bool { return false; } | ||||
|   void init_buffer() {} | ||||
| 
 | ||||
|   auto get_read_buffer() const -> span<const char> { | ||||
|     return {&next_, has_next_ ? 1u : 0u}; | ||||
|   } | ||||
| 
 | ||||
|   auto get_write_buffer() const -> span<char> { return {nullptr, 0}; } | ||||
| 
 | ||||
|   void advance_write_buffer(size_t) {} | ||||
| 
 | ||||
|   auto get() -> int { | ||||
|     has_next_ = false; | ||||
|     return file_base<F>::get(); | ||||
|   } | ||||
| 
 | ||||
|   void unget(char c) { | ||||
|     file_base<F>::unget(c); | ||||
|     next_ = c; | ||||
|     has_next_ = true; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| #ifndef FMT_USE_FALLBACK_FILE | ||||
| #  define FMT_USE_FALLBACK_FILE 0 | ||||
| #endif | ||||
| 
 | ||||
| template <typename F, | ||||
|           FMT_ENABLE_IF(sizeof(F::_p) != 0 && !FMT_USE_FALLBACK_FILE)> | ||||
| auto get_file(F* f, int) -> apple_file<F> { | ||||
|   return f; | ||||
| } | ||||
| template <typename F, | ||||
|           FMT_ENABLE_IF(sizeof(F::_IO_read_ptr) != 0 && !FMT_USE_FALLBACK_FILE)> | ||||
| inline auto get_file(F* f, int) -> glibc_file<F> { | ||||
|   return f; | ||||
| } | ||||
| 
 | ||||
| inline auto get_file(FILE* f, ...) -> fallback_file<FILE> { return f; } | ||||
| 
 | ||||
| using file_ref = decltype(get_file(static_cast<FILE*>(nullptr), 0)); | ||||
| 
 | ||||
| template <typename F = FILE, typename Enable = void> | ||||
| class file_print_buffer : public buffer<char> { | ||||
|  public: | ||||
|   explicit file_print_buffer(F*) : buffer(nullptr, size_t()) {} | ||||
| }; | ||||
| 
 | ||||
| template <typename F> | ||||
| class file_print_buffer<F, enable_if_t<has_flockfile<F>::value>> | ||||
|     : public buffer<char> { | ||||
|  private: | ||||
|   file_ref file_; | ||||
| 
 | ||||
|   static void grow(buffer<char>& base, size_t) { | ||||
|     auto& self = static_cast<file_print_buffer&>(base); | ||||
|     self.file_.advance_write_buffer(self.size()); | ||||
|     if (self.file_.get_write_buffer().size == 0) self.file_.flush(); | ||||
|     auto buf = self.file_.get_write_buffer(); | ||||
|     FMT_ASSERT(buf.size > 0, ""); | ||||
|     self.set(buf.data, buf.size); | ||||
|     self.clear(); | ||||
|   } | ||||
| 
 | ||||
|  public: | ||||
|   explicit file_print_buffer(F* f) : buffer(grow, size_t()), file_(f) { | ||||
|     flockfile(f); | ||||
|     file_.init_buffer(); | ||||
|     auto buf = file_.get_write_buffer(); | ||||
|     set(buf.data, buf.size); | ||||
|   } | ||||
|   ~file_print_buffer() { | ||||
|     file_.advance_write_buffer(size()); | ||||
|     bool flush = file_.needs_flush(); | ||||
|     F* f = file_;    // Make funlockfile depend on the template parameter F
 | ||||
|     funlockfile(f);  // for the system API detection to work.
 | ||||
|     if (flush) fflush(file_); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| #if !defined(_WIN32) || defined(FMT_USE_WRITE_CONSOLE) | ||||
| FMT_FUNC auto write_console(int, string_view) -> bool { return false; } | ||||
| #else | ||||
| using dword = conditional_t<sizeof(long) == 4, unsigned long, unsigned>; | ||||
| extern "C" __declspec(dllimport) int __stdcall WriteConsoleW(  //
 | ||||
|     void*, const void*, dword, dword*, void*); | ||||
| 
 | ||||
| FMT_FUNC bool write_console(std::FILE* f, string_view text) { | ||||
|   auto fd = _fileno(f); | ||||
|   if (!_isatty(fd)) return false; | ||||
| FMT_FUNC bool write_console(int fd, string_view text) { | ||||
|   auto u16 = utf8_to_utf16(text); | ||||
|   auto written = dword(); | ||||
|   return WriteConsoleW(reinterpret_cast<void*>(_get_osfhandle(fd)), u16.c_str(), | ||||
|                        static_cast<uint32_t>(u16.size()), &written, nullptr) != 0; | ||||
|                        static_cast<dword>(u16.size()), nullptr, nullptr) != 0; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| // Print assuming legacy (non-Unicode) encoding.
 | ||||
| FMT_FUNC void vprint_mojibake(std::FILE* f, string_view fmt, format_args args) { | ||||
| FMT_FUNC void vprint_mojibake(std::FILE* f, string_view fmt, format_args args, | ||||
|                               bool newline) { | ||||
|   auto buffer = memory_buffer(); | ||||
|   detail::vformat_to(buffer, fmt, | ||||
|                      basic_format_args<buffer_context<char>>(args)); | ||||
|   fwrite_fully(buffer.data(), 1, buffer.size(), f); | ||||
|   detail::vformat_to(buffer, fmt, args); | ||||
|   if (newline) buffer.push_back('\n'); | ||||
|   fwrite_all(buffer.data(), buffer.size(), f); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| FMT_FUNC void print(std::FILE* f, string_view text) { | ||||
|   if (!write_console(f, text)) fwrite_fully(text.data(), 1, text.size(), f); | ||||
| #if defined(_WIN32) && !defined(FMT_USE_WRITE_CONSOLE) | ||||
|   int fd = _fileno(f); | ||||
|   if (_isatty(fd)) { | ||||
|     std::fflush(f); | ||||
|     if (write_console(fd, text)) return; | ||||
|   } | ||||
| #endif | ||||
|   fwrite_all(text.data(), text.size(), f); | ||||
| } | ||||
| }  // namespace detail
 | ||||
| 
 | ||||
| FMT_FUNC void vprint(std::FILE* f, string_view fmt, format_args args) { | ||||
| FMT_FUNC void vprint_buffered(std::FILE* f, string_view fmt, format_args args) { | ||||
|   auto buffer = memory_buffer(); | ||||
|   detail::vformat_to(buffer, fmt, args); | ||||
|   detail::print(f, {buffer.data(), buffer.size()}); | ||||
| } | ||||
| 
 | ||||
| FMT_FUNC void vprint(std::FILE* f, string_view fmt, format_args args) { | ||||
|   if (!detail::file_ref(f).is_buffered() || !detail::has_flockfile<>()) | ||||
|     return vprint_buffered(f, fmt, args); | ||||
|   auto&& buffer = detail::file_print_buffer<>(f); | ||||
|   return detail::vformat_to(buffer, fmt, args); | ||||
| } | ||||
| 
 | ||||
| FMT_FUNC void vprintln(std::FILE* f, string_view fmt, format_args args) { | ||||
|   auto buffer = memory_buffer(); | ||||
|   detail::vformat_to(buffer, fmt, args); | ||||
|   buffer.push_back('\n'); | ||||
|   detail::print(f, {buffer.data(), buffer.size()}); | ||||
| } | ||||
| 
 | ||||
| FMT_FUNC void vprint(string_view fmt, format_args args) { | ||||
|   vprint(stdout, fmt, args); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										3356
									
								
								thirdparty/fmt/include/fmt/format.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3356
									
								
								thirdparty/fmt/include/fmt/format.h
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										296
									
								
								thirdparty/fmt/include/fmt/os.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										296
									
								
								thirdparty/fmt/include/fmt/os.h
									
										
									
									
										vendored
									
									
								
							|  | @ -8,17 +8,19 @@ | |||
| #ifndef FMT_OS_H_ | ||||
| #define FMT_OS_H_ | ||||
| 
 | ||||
| #include <cerrno> | ||||
| #include <cstddef> | ||||
| #include <cstdio> | ||||
| #include <system_error>  // std::system_error | ||||
| 
 | ||||
| #if defined __APPLE__ || defined(__FreeBSD__) | ||||
| #  include <xlocale.h>  // for LC_NUMERIC_MASK on OS X
 | ||||
| #endif | ||||
| 
 | ||||
| #include "format.h" | ||||
| 
 | ||||
| #ifndef FMT_MODULE | ||||
| #  include <cerrno> | ||||
| #  include <cstddef> | ||||
| #  include <cstdio> | ||||
| #  include <system_error>  // std::system_error
 | ||||
| 
 | ||||
| #  if FMT_HAS_INCLUDE(<xlocale.h>) | ||||
| #    include <xlocale.h>  // LC_NUMERIC_MASK on macOS
 | ||||
| #  endif | ||||
| #endif  // FMT_MODULE
 | ||||
| 
 | ||||
| #ifndef FMT_USE_FCNTL | ||||
| // UWP doesn't provide _pipe.
 | ||||
| #  if FMT_HAS_INCLUDE("winapifamily.h") | ||||
|  | @ -46,6 +48,7 @@ | |||
| 
 | ||||
| // Calls to system functions are wrapped in FMT_SYSTEM for testability.
 | ||||
| #ifdef FMT_SYSTEM | ||||
| #  define FMT_HAS_SYSTEM | ||||
| #  define FMT_POSIX_CALL(call) FMT_SYSTEM(call) | ||||
| #else | ||||
| #  define FMT_SYSTEM(call) ::call | ||||
|  | @ -74,47 +77,34 @@ FMT_BEGIN_NAMESPACE | |||
| FMT_BEGIN_EXPORT | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   A reference to a null-terminated string. It can be constructed from a C | ||||
|   string or ``std::string``. | ||||
| 
 | ||||
|   You can use one of the following type aliases for common character types: | ||||
| 
 | ||||
|   +---------------+-----------------------------+ | ||||
|   | Type          | Definition                  | | ||||
|   +===============+=============================+ | ||||
|   | cstring_view  | basic_cstring_view<char>    | | ||||
|   +---------------+-----------------------------+ | ||||
|   | wcstring_view | basic_cstring_view<wchar_t> | | ||||
|   +---------------+-----------------------------+ | ||||
| 
 | ||||
|   This class is most useful as a parameter type to allow passing | ||||
|   different types of strings to a function, for example:: | ||||
| 
 | ||||
|     template <typename... Args> | ||||
|     std::string format(cstring_view format_str, const Args & ... args); | ||||
| 
 | ||||
|     format("{}", 42); | ||||
|     format(std::string("{}"), 42); | ||||
|   \endrst | ||||
|  * A reference to a null-terminated string. It can be constructed from a C | ||||
|  * string or `std::string`. | ||||
|  * | ||||
|  * You can use one of the following type aliases for common character types: | ||||
|  * | ||||
|  * +---------------+-----------------------------+ | ||||
|  * | Type          | Definition                  | | ||||
|  * +===============+=============================+ | ||||
|  * | cstring_view  | basic_cstring_view<char>    | | ||||
|  * +---------------+-----------------------------+ | ||||
|  * | wcstring_view | basic_cstring_view<wchar_t> | | ||||
|  * +---------------+-----------------------------+ | ||||
|  * | ||||
|  * This class is most useful as a parameter type for functions that wrap C APIs. | ||||
|  */ | ||||
| template <typename Char> class basic_cstring_view { | ||||
|  private: | ||||
|   const Char* data_; | ||||
| 
 | ||||
|  public: | ||||
|   /** Constructs a string reference object from a C string. */ | ||||
|   /// Constructs a string reference object from a C string.
 | ||||
|   basic_cstring_view(const Char* s) : data_(s) {} | ||||
| 
 | ||||
|   /**
 | ||||
|     \rst | ||||
|     Constructs a string reference from an ``std::string`` object. | ||||
|     \endrst | ||||
|    */ | ||||
|   /// Constructs a string reference from an `std::string` object.
 | ||||
|   basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {} | ||||
| 
 | ||||
|   /** Returns the pointer to a C string. */ | ||||
|   const Char* c_str() const { return data_; } | ||||
|   /// Returns the pointer to a C string.
 | ||||
|   auto c_str() const -> const Char* { return data_; } | ||||
| }; | ||||
| 
 | ||||
| using cstring_view = basic_cstring_view<char>; | ||||
|  | @ -128,48 +118,45 @@ FMT_API void format_windows_error(buffer<char>& out, int error_code, | |||
|                                   const char* message) noexcept; | ||||
| } | ||||
| 
 | ||||
| FMT_API std::system_error vwindows_error(int error_code, string_view format_str, | ||||
| FMT_API std::system_error vwindows_error(int error_code, string_view fmt, | ||||
|                                          format_args args); | ||||
| 
 | ||||
| /**
 | ||||
|  \rst | ||||
|  Constructs a :class:`std::system_error` object with the description | ||||
|  of the form | ||||
| 
 | ||||
|  .. parsed-literal:: | ||||
|    *<message>*: *<system-message>* | ||||
| 
 | ||||
|  where *<message>* is the formatted message and *<system-message>* is the | ||||
|  system message corresponding to the error code. | ||||
|  *error_code* is a Windows error code as given by ``GetLastError``. | ||||
|  If *error_code* is not a valid error code such as -1, the system message | ||||
|  will look like "error -1". | ||||
| 
 | ||||
|  **Example**:: | ||||
| 
 | ||||
|    // This throws a system_error with the description
 | ||||
|    //   cannot open file 'madeup': The system cannot find the file specified.
 | ||||
|    // or similar (system message may vary).
 | ||||
|    const char *filename = "madeup"; | ||||
|    LPOFSTRUCT of = LPOFSTRUCT(); | ||||
|    HFILE file = OpenFile(filename, &of, OF_READ); | ||||
|    if (file == HFILE_ERROR) { | ||||
|      throw fmt::windows_error(GetLastError(), | ||||
|                               "cannot open file '{}'", filename); | ||||
|    } | ||||
|  \endrst | ||||
| */ | ||||
| template <typename... Args> | ||||
| std::system_error windows_error(int error_code, string_view message, | ||||
|                                 const Args&... args) { | ||||
|   return vwindows_error(error_code, message, fmt::make_format_args(args...)); | ||||
|  * Constructs a `std::system_error` object with the description of the form | ||||
|  * | ||||
|  *     <message>: <system-message> | ||||
|  * | ||||
|  * where `<message>` is the formatted message and `<system-message>` is the | ||||
|  * system message corresponding to the error code. | ||||
|  * `error_code` is a Windows error code as given by `GetLastError`. | ||||
|  * If `error_code` is not a valid error code such as -1, the system message | ||||
|  * will look like "error -1". | ||||
|  * | ||||
|  * **Example**: | ||||
|  * | ||||
|  *     // This throws a system_error with the description
 | ||||
|  *     //   cannot open file 'madeup': The system cannot find the file
 | ||||
|  * specified. | ||||
|  *     // or similar (system message may vary).
 | ||||
|  *     const char *filename = "madeup"; | ||||
|  *     LPOFSTRUCT of = LPOFSTRUCT(); | ||||
|  *     HFILE file = OpenFile(filename, &of, OF_READ); | ||||
|  *     if (file == HFILE_ERROR) { | ||||
|  *       throw fmt::windows_error(GetLastError(), | ||||
|  *                                "cannot open file '{}'", filename); | ||||
|  *     } | ||||
|  */ | ||||
| template <typename... T> | ||||
| auto windows_error(int error_code, string_view message, const T&... args) | ||||
|     -> std::system_error { | ||||
|   return vwindows_error(error_code, message, vargs<T...>{{args...}}); | ||||
| } | ||||
| 
 | ||||
| // Reports a Windows error without throwing an exception.
 | ||||
| // Can be used to report errors from destructors.
 | ||||
| FMT_API void report_windows_error(int error_code, const char* message) noexcept; | ||||
| #else | ||||
| inline const std::error_category& system_category() noexcept { | ||||
| inline auto system_category() noexcept -> const std::error_category& { | ||||
|   return std::system_category(); | ||||
| } | ||||
| #endif  // _WIN32
 | ||||
|  | @ -177,8 +164,8 @@ inline const std::error_category& system_category() noexcept { | |||
| // std::system is not available on some platforms such as iOS (#2248).
 | ||||
| #ifdef __OSX__ | ||||
| template <typename S, typename... Args, typename Char = char_t<S>> | ||||
| void say(const S& format_str, Args&&... args) { | ||||
|   std::system(format("say \"{}\"", format(format_str, args...)).c_str()); | ||||
| void say(const S& fmt, Args&&... args) { | ||||
|   std::system(format("say \"{}\"", format(fmt, args...)).c_str()); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
|  | @ -189,24 +176,24 @@ class buffered_file { | |||
| 
 | ||||
|   friend class file; | ||||
| 
 | ||||
|   explicit buffered_file(FILE* f) : file_(f) {} | ||||
|   inline explicit buffered_file(FILE* f) : file_(f) {} | ||||
| 
 | ||||
|  public: | ||||
|   buffered_file(const buffered_file&) = delete; | ||||
|   void operator=(const buffered_file&) = delete; | ||||
| 
 | ||||
|   // Constructs a buffered_file object which doesn't represent any file.
 | ||||
|   buffered_file() noexcept : file_(nullptr) {} | ||||
|   inline buffered_file() noexcept : file_(nullptr) {} | ||||
| 
 | ||||
|   // Destroys the object closing the file it represents if any.
 | ||||
|   FMT_API ~buffered_file() noexcept; | ||||
| 
 | ||||
|  public: | ||||
|   buffered_file(buffered_file&& other) noexcept : file_(other.file_) { | ||||
|   inline buffered_file(buffered_file&& other) noexcept : file_(other.file_) { | ||||
|     other.file_ = nullptr; | ||||
|   } | ||||
| 
 | ||||
|   buffered_file& operator=(buffered_file&& other) { | ||||
|   inline auto operator=(buffered_file&& other) -> buffered_file& { | ||||
|     close(); | ||||
|     file_ = other.file_; | ||||
|     other.file_ = nullptr; | ||||
|  | @ -220,21 +207,20 @@ class buffered_file { | |||
|   FMT_API void close(); | ||||
| 
 | ||||
|   // Returns the pointer to a FILE object representing this file.
 | ||||
|   FILE* get() const noexcept { return file_; } | ||||
|   inline auto get() const noexcept -> FILE* { return file_; } | ||||
| 
 | ||||
|   FMT_API int descriptor() const; | ||||
|   FMT_API auto descriptor() const -> int; | ||||
| 
 | ||||
|   void vprint(string_view format_str, format_args args) { | ||||
|     fmt::vprint(file_, format_str, args); | ||||
|   } | ||||
| 
 | ||||
|   template <typename... Args> | ||||
|   inline void print(string_view format_str, const Args&... args) { | ||||
|     vprint(format_str, fmt::make_format_args(args...)); | ||||
|   template <typename... T> | ||||
|   inline void print(string_view fmt, const T&... args) { | ||||
|     fmt::vargs<T...> vargs = {{args...}}; | ||||
|     detail::is_locking<T...>() ? fmt::vprint_buffered(file_, fmt, vargs) | ||||
|                                : fmt::vprint(file_, fmt, vargs); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| #if FMT_USE_FCNTL | ||||
| 
 | ||||
| // A file. Closed file is represented by a file object with descriptor -1.
 | ||||
| // Methods that are not declared with noexcept may throw
 | ||||
| // fmt::system_error in case of failure. Note that some errors such as
 | ||||
|  | @ -248,6 +234,8 @@ class FMT_API file { | |||
|   // Constructs a file object with a given descriptor.
 | ||||
|   explicit file(int fd) : fd_(fd) {} | ||||
| 
 | ||||
|   friend struct pipe; | ||||
| 
 | ||||
|  public: | ||||
|   // Possible values for the oflag argument to the constructor.
 | ||||
|   enum { | ||||
|  | @ -260,7 +248,7 @@ class FMT_API file { | |||
|   }; | ||||
| 
 | ||||
|   // Constructs a file object which doesn't represent any file.
 | ||||
|   file() noexcept : fd_(-1) {} | ||||
|   inline file() noexcept : fd_(-1) {} | ||||
| 
 | ||||
|   // Opens a file and constructs a file object representing this file.
 | ||||
|   file(cstring_view path, int oflag); | ||||
|  | @ -269,10 +257,10 @@ class FMT_API file { | |||
|   file(const file&) = delete; | ||||
|   void operator=(const file&) = delete; | ||||
| 
 | ||||
|   file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; } | ||||
|   inline file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; } | ||||
| 
 | ||||
|   // Move assignment is not noexcept because close may throw.
 | ||||
|   file& operator=(file&& other) { | ||||
|   inline auto operator=(file&& other) -> file& { | ||||
|     close(); | ||||
|     fd_ = other.fd_; | ||||
|     other.fd_ = -1; | ||||
|  | @ -283,24 +271,24 @@ class FMT_API file { | |||
|   ~file() noexcept; | ||||
| 
 | ||||
|   // Returns the file descriptor.
 | ||||
|   int descriptor() const noexcept { return fd_; } | ||||
|   inline auto descriptor() const noexcept -> int { return fd_; } | ||||
| 
 | ||||
|   // Closes the file.
 | ||||
|   void close(); | ||||
| 
 | ||||
|   // Returns the file size. The size has signed type for consistency with
 | ||||
|   // stat::st_size.
 | ||||
|   long long size() const; | ||||
|   auto size() const -> long long; | ||||
| 
 | ||||
|   // Attempts to read count bytes from the file into the specified buffer.
 | ||||
|   size_t read(void* buffer, size_t count); | ||||
|   auto read(void* buffer, size_t count) -> size_t; | ||||
| 
 | ||||
|   // Attempts to write count bytes from the specified buffer to the file.
 | ||||
|   size_t write(const void* buffer, size_t count); | ||||
|   auto write(const void* buffer, size_t count) -> size_t; | ||||
| 
 | ||||
|   // Duplicates a file descriptor with the dup function and returns
 | ||||
|   // the duplicate as a file object.
 | ||||
|   static file dup(int fd); | ||||
|   static auto dup(int fd) -> file; | ||||
| 
 | ||||
|   // Makes fd be the copy of this file descriptor, closing fd first if
 | ||||
|   // necessary.
 | ||||
|  | @ -310,13 +298,9 @@ class FMT_API file { | |||
|   // necessary.
 | ||||
|   void dup2(int fd, std::error_code& ec) noexcept; | ||||
| 
 | ||||
|   // Creates a pipe setting up read_end and write_end file objects for reading
 | ||||
|   // and writing respectively.
 | ||||
|   static void pipe(file& read_end, file& write_end); | ||||
| 
 | ||||
|   // Creates a buffered_file object associated with this file and detaches
 | ||||
|   // this file object from the file.
 | ||||
|   buffered_file fdopen(const char* mode); | ||||
|   auto fdopen(const char* mode) -> buffered_file; | ||||
| 
 | ||||
| #  if defined(_WIN32) && !defined(__MINGW32__) | ||||
|   // Opens a file and constructs a file object representing this file by
 | ||||
|  | @ -325,15 +309,24 @@ class FMT_API file { | |||
| #  endif | ||||
| }; | ||||
| 
 | ||||
| struct FMT_API pipe { | ||||
|   file read_end; | ||||
|   file write_end; | ||||
| 
 | ||||
|   // Creates a pipe setting up read_end and write_end file objects for reading
 | ||||
|   // and writing respectively.
 | ||||
|   pipe(); | ||||
| }; | ||||
| 
 | ||||
| // Returns the memory page size.
 | ||||
| long getpagesize(); | ||||
| auto getpagesize() -> long; | ||||
| 
 | ||||
| namespace detail { | ||||
| 
 | ||||
| struct buffer_size { | ||||
|   buffer_size() = default; | ||||
|   constexpr buffer_size() = default; | ||||
|   size_t value = 0; | ||||
|   buffer_size operator=(size_t val) const { | ||||
|   FMT_CONSTEXPR auto operator=(size_t val) const -> buffer_size { | ||||
|     auto bs = buffer_size(); | ||||
|     bs.value = val; | ||||
|     return bs; | ||||
|  | @ -344,7 +337,7 @@ struct ostream_params { | |||
|   int oflag = file::WRONLY | file::CREATE | file::TRUNC; | ||||
|   size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768; | ||||
| 
 | ||||
|   ostream_params() {} | ||||
|   constexpr ostream_params() {} | ||||
| 
 | ||||
|   template <typename... T> | ||||
|   ostream_params(T... params, int new_oflag) : ostream_params(params...) { | ||||
|  | @ -365,82 +358,65 @@ struct ostream_params { | |||
| #  endif | ||||
| }; | ||||
| 
 | ||||
| class file_buffer final : public buffer<char> { | ||||
| }  // namespace detail
 | ||||
| 
 | ||||
| FMT_INLINE_VARIABLE constexpr auto buffer_size = detail::buffer_size(); | ||||
| 
 | ||||
| /// A fast buffered output stream for writing from a single thread. Writing from
 | ||||
| /// multiple threads without external synchronization may result in a data race.
 | ||||
| class FMT_API ostream : private detail::buffer<char> { | ||||
|  private: | ||||
|   file file_; | ||||
| 
 | ||||
|   FMT_API void grow(size_t) override; | ||||
|   ostream(cstring_view path, const detail::ostream_params& params); | ||||
| 
 | ||||
|   static void grow(buffer<char>& buf, size_t); | ||||
| 
 | ||||
|  public: | ||||
|   FMT_API file_buffer(cstring_view path, const ostream_params& params); | ||||
|   FMT_API file_buffer(file_buffer&& other); | ||||
|   FMT_API ~file_buffer(); | ||||
|   ostream(ostream&& other) noexcept; | ||||
|   ~ostream(); | ||||
| 
 | ||||
|   void flush() { | ||||
|   operator writer() { | ||||
|     detail::buffer<char>& buf = *this; | ||||
|     return buf; | ||||
|   } | ||||
| 
 | ||||
|   inline void flush() { | ||||
|     if (size() == 0) return; | ||||
|     file_.write(data(), size() * sizeof(data()[0])); | ||||
|     clear(); | ||||
|   } | ||||
| 
 | ||||
|   void close() { | ||||
|   template <typename... T> | ||||
|   friend auto output_file(cstring_view path, T... params) -> ostream; | ||||
| 
 | ||||
|   inline void close() { | ||||
|     flush(); | ||||
|     file_.close(); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| }  // namespace detail
 | ||||
| 
 | ||||
| // Added {} below to work around default constructor error known to
 | ||||
| // occur in Xcode versions 7.2.1 and 8.2.1.
 | ||||
| constexpr detail::buffer_size buffer_size{}; | ||||
| 
 | ||||
| /** A fast output stream which is not thread-safe. */ | ||||
| class FMT_API ostream { | ||||
|  private: | ||||
|   FMT_MSC_WARNING(suppress : 4251) | ||||
|   detail::file_buffer buffer_; | ||||
| 
 | ||||
|   ostream(cstring_view path, const detail::ostream_params& params) | ||||
|       : buffer_(path, params) {} | ||||
| 
 | ||||
|  public: | ||||
|   ostream(ostream&& other) : buffer_(std::move(other.buffer_)) {} | ||||
| 
 | ||||
|   ~ostream(); | ||||
| 
 | ||||
|   void flush() { buffer_.flush(); } | ||||
| 
 | ||||
|   template <typename... T> | ||||
|   friend ostream output_file(cstring_view path, T... params); | ||||
| 
 | ||||
|   void close() { buffer_.close(); } | ||||
| 
 | ||||
|   /**
 | ||||
|     Formats ``args`` according to specifications in ``fmt`` and writes the | ||||
|     output to the file. | ||||
|    */ | ||||
|   /// Formats `args` according to specifications in `fmt` and writes the
 | ||||
|   /// output to the file.
 | ||||
|   template <typename... T> void print(format_string<T...> fmt, T&&... args) { | ||||
|     vformat_to(detail::buffer_appender<char>(buffer_), fmt, | ||||
|                fmt::make_format_args(args...)); | ||||
|     vformat_to(appender(*this), fmt.str, vargs<T...>{{args...}}); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Opens a file for writing. Supported parameters passed in *params*: | ||||
| 
 | ||||
|   * ``<integer>``: Flags passed to `open | ||||
|     <https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_
 | ||||
|     (``file::WRONLY | file::CREATE | file::TRUNC`` by default) | ||||
|   * ``buffer_size=<integer>``: Output buffer size | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     auto out = fmt::output_file("guide.txt"); | ||||
|     out.print("Don't {}", "Panic"); | ||||
|   \endrst | ||||
|  * Opens a file for writing. Supported parameters passed in `params`: | ||||
|  * | ||||
|  * - `<integer>`: Flags passed to [open]( | ||||
|  *   https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html)
 | ||||
|  *   (`file::WRONLY | file::CREATE | file::TRUNC` by default) | ||||
|  * - `buffer_size=<integer>`: Output buffer size | ||||
|  * | ||||
|  * **Example**: | ||||
|  * | ||||
|  *     auto out = fmt::output_file("guide.txt"); | ||||
|  *     out.print("Don't {}", "Panic"); | ||||
|  */ | ||||
| template <typename... T> | ||||
| inline ostream output_file(cstring_view path, T... params) { | ||||
| inline auto output_file(cstring_view path, T... params) -> ostream { | ||||
|   return {path, detail::ostream_params(params...)}; | ||||
| } | ||||
| #endif  // FMT_USE_FCNTL
 | ||||
|  |  | |||
							
								
								
									
										191
									
								
								thirdparty/fmt/include/fmt/ostream.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										191
									
								
								thirdparty/fmt/include/fmt/ostream.h
									
										
									
									
										vendored
									
									
								
							|  | @ -8,19 +8,29 @@ | |||
| #ifndef FMT_OSTREAM_H_ | ||||
| #define FMT_OSTREAM_H_ | ||||
| 
 | ||||
| #include <fstream>  // std::filebuf | ||||
| 
 | ||||
| #if defined(_WIN32) && defined(__GLIBCXX__) | ||||
| #  include <ext/stdio_filebuf.h> | ||||
| #  include <ext/stdio_sync_filebuf.h> | ||||
| #elif defined(_WIN32) && defined(_LIBCPP_VERSION) | ||||
| #  include <__std_stream> | ||||
| #ifndef FMT_MODULE | ||||
| #  include <fstream>  // std::filebuf
 | ||||
| #endif | ||||
| 
 | ||||
| #include "format.h" | ||||
| #ifdef _WIN32 | ||||
| #  ifdef __GLIBCXX__ | ||||
| #    include <ext/stdio_filebuf.h> | ||||
| #    include <ext/stdio_sync_filebuf.h> | ||||
| #  endif | ||||
| #  include <io.h> | ||||
| #endif | ||||
| 
 | ||||
| #include "chrono.h"  // formatbuf | ||||
| 
 | ||||
| #ifdef _MSVC_STL_UPDATE | ||||
| #  define FMT_MSVC_STL_UPDATE _MSVC_STL_UPDATE | ||||
| #elif defined(_MSC_VER) && _MSC_VER < 1912  // VS 15.5
 | ||||
| #  define FMT_MSVC_STL_UPDATE _MSVC_LANG | ||||
| #else | ||||
| #  define FMT_MSVC_STL_UPDATE 0 | ||||
| #endif | ||||
| 
 | ||||
| FMT_BEGIN_NAMESPACE | ||||
| 
 | ||||
| namespace detail { | ||||
| 
 | ||||
| // Generate a unique explicit instantion in every translation unit using a tag
 | ||||
|  | @ -33,49 +43,18 @@ class file_access { | |||
|   friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; } | ||||
| }; | ||||
| 
 | ||||
| #if FMT_MSC_VERSION | ||||
| #if FMT_MSVC_STL_UPDATE | ||||
| template class file_access<file_access_tag, std::filebuf, | ||||
|                            &std::filebuf::_Myfile>; | ||||
| auto get_file(std::filebuf&) -> FILE*; | ||||
| #elif defined(_WIN32) && defined(_LIBCPP_VERSION) | ||||
| template class file_access<file_access_tag, std::__stdoutbuf<char>, | ||||
|                            &std::__stdoutbuf<char>::__file_>; | ||||
| auto get_file(std::__stdoutbuf<char>&) -> FILE*; | ||||
| #endif | ||||
| 
 | ||||
| inline bool write_ostream_unicode(std::ostream& os, fmt::string_view data) { | ||||
| #if FMT_MSC_VERSION | ||||
|   if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf())) | ||||
|     if (FILE* f = get_file(*buf)) return write_console(f, data); | ||||
| #elif defined(_WIN32) && defined(__GLIBCXX__) | ||||
|   auto* rdbuf = os.rdbuf(); | ||||
|   FILE* c_file; | ||||
|   if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf)) | ||||
|     c_file = sfbuf->file(); | ||||
|   else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf)) | ||||
|     c_file = fbuf->file(); | ||||
|   else | ||||
|     return false; | ||||
|   if (c_file) return write_console(c_file, data); | ||||
| #elif defined(_WIN32) && defined(_LIBCPP_VERSION) | ||||
|   if (auto* buf = dynamic_cast<std::__stdoutbuf<char>*>(os.rdbuf())) | ||||
|     if (FILE* f = get_file(*buf)) return write_console(f, data); | ||||
| #else | ||||
|   ignore_unused(os, data); | ||||
| #endif | ||||
|   return false; | ||||
| } | ||||
| inline bool write_ostream_unicode(std::wostream&, | ||||
|                                   fmt::basic_string_view<wchar_t>) { | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| // Write the content of buf to os.
 | ||||
| // It is a separate function rather than a part of vprint to simplify testing.
 | ||||
| template <typename Char> | ||||
| void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) { | ||||
|   const Char* buf_data = buf.data(); | ||||
|   using unsigned_streamsize = std::make_unsigned<std::streamsize>::type; | ||||
|   using unsigned_streamsize = make_unsigned_t<std::streamsize>; | ||||
|   unsigned_streamsize size = buf.size(); | ||||
|   unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>()); | ||||
|   do { | ||||
|  | @ -86,20 +65,9 @@ void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) { | |||
|   } while (size != 0); | ||||
| } | ||||
| 
 | ||||
| template <typename Char, typename T> | ||||
| void format_value(buffer<Char>& buf, const T& value, | ||||
|                   locale_ref loc = locale_ref()) { | ||||
|   auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf); | ||||
|   auto&& output = std::basic_ostream<Char>(&format_buf); | ||||
| #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) | ||||
|   if (loc) output.imbue(loc.get<std::locale>()); | ||||
| #endif | ||||
|   output << value; | ||||
|   output.exceptions(std::ios_base::failbit | std::ios_base::badbit); | ||||
| } | ||||
| 
 | ||||
| template <typename T> struct streamed_view { const T& value; }; | ||||
| 
 | ||||
| template <typename T> struct streamed_view { | ||||
|   const T& value; | ||||
| }; | ||||
| }  // namespace detail
 | ||||
| 
 | ||||
| // Formats an object of type T that has an overloaded ostream operator<<.
 | ||||
|  | @ -107,11 +75,14 @@ template <typename Char> | |||
| struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> { | ||||
|   void set_debug_format() = delete; | ||||
| 
 | ||||
|   template <typename T, typename OutputIt> | ||||
|   auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) const | ||||
|       -> OutputIt { | ||||
|   template <typename T, typename Context> | ||||
|   auto format(const T& value, Context& ctx) const -> decltype(ctx.out()) { | ||||
|     auto buffer = basic_memory_buffer<Char>(); | ||||
|     detail::format_value(buffer, value, ctx.locale()); | ||||
|     auto&& formatbuf = detail::formatbuf<std::basic_streambuf<Char>>(buffer); | ||||
|     auto&& output = std::basic_ostream<Char>(&formatbuf); | ||||
|     output.imbue(std::locale::classic());  // The default is always unlocalized.
 | ||||
|     output << value; | ||||
|     output.exceptions(std::ios_base::failbit | std::ios_base::badbit); | ||||
|     return formatter<basic_string_view<Char>, Char>::format( | ||||
|         {buffer.data(), buffer.size()}, ctx); | ||||
|   } | ||||
|  | @ -122,73 +93,67 @@ using ostream_formatter = basic_ostream_formatter<char>; | |||
| template <typename T, typename Char> | ||||
| struct formatter<detail::streamed_view<T>, Char> | ||||
|     : basic_ostream_formatter<Char> { | ||||
|   template <typename OutputIt> | ||||
|   auto format(detail::streamed_view<T> view, | ||||
|               basic_format_context<OutputIt, Char>& ctx) const -> OutputIt { | ||||
|   template <typename Context> | ||||
|   auto format(detail::streamed_view<T> view, Context& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     return basic_ostream_formatter<Char>::format(view.value, ctx); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Returns a view that formats `value` via an ostream ``operator<<``. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     fmt::print("Current thread id: {}\n", | ||||
|                fmt::streamed(std::this_thread::get_id())); | ||||
|   \endrst | ||||
|  * Returns a view that formats `value` via an ostream `operator<<`. | ||||
|  * | ||||
|  * **Example**: | ||||
|  * | ||||
|  *     fmt::print("Current thread id: {}\n", | ||||
|  *                fmt::streamed(std::this_thread::get_id())); | ||||
|  */ | ||||
| template <typename T> | ||||
| auto streamed(const T& value) -> detail::streamed_view<T> { | ||||
| constexpr auto streamed(const T& value) -> detail::streamed_view<T> { | ||||
|   return {value}; | ||||
| } | ||||
| 
 | ||||
| namespace detail { | ||||
| 
 | ||||
| inline void vprint_directly(std::ostream& os, string_view format_str, | ||||
|                             format_args args) { | ||||
| inline void vprint(std::ostream& os, string_view fmt, format_args args) { | ||||
|   auto buffer = memory_buffer(); | ||||
|   detail::vformat_to(buffer, format_str, args); | ||||
|   detail::write_buffer(os, buffer); | ||||
| } | ||||
| 
 | ||||
| }  // namespace detail
 | ||||
| 
 | ||||
| FMT_EXPORT template <typename Char> | ||||
| void vprint(std::basic_ostream<Char>& os, | ||||
|             basic_string_view<type_identity_t<Char>> format_str, | ||||
|             basic_format_args<buffer_context<type_identity_t<Char>>> args) { | ||||
|   auto buffer = basic_memory_buffer<Char>(); | ||||
|   detail::vformat_to(buffer, format_str, args); | ||||
|   if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return; | ||||
|   detail::vformat_to(buffer, fmt, args); | ||||
|   FILE* f = nullptr; | ||||
| #if FMT_MSVC_STL_UPDATE && FMT_USE_RTTI | ||||
|   if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf())) | ||||
|     f = detail::get_file(*buf); | ||||
| #elif defined(_WIN32) && defined(__GLIBCXX__) && FMT_USE_RTTI | ||||
|   auto* rdbuf = os.rdbuf(); | ||||
|   if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf)) | ||||
|     f = sfbuf->file(); | ||||
|   else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf)) | ||||
|     f = fbuf->file(); | ||||
| #endif | ||||
| #ifdef _WIN32 | ||||
|   if (f) { | ||||
|     int fd = _fileno(f); | ||||
|     if (_isatty(fd)) { | ||||
|       os.flush(); | ||||
|       if (detail::write_console(fd, {buffer.data(), buffer.size()})) return; | ||||
|     } | ||||
|   } | ||||
| #endif | ||||
|   detail::ignore_unused(f); | ||||
|   detail::write_buffer(os, buffer); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Prints formatted data to the stream *os*. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     fmt::print(cerr, "Don't {}!", "panic"); | ||||
|   \endrst | ||||
|  * Prints formatted data to the stream `os`. | ||||
|  * | ||||
|  * **Example**: | ||||
|  * | ||||
|  *     fmt::print(cerr, "Don't {}!", "panic"); | ||||
|  */ | ||||
| FMT_EXPORT template <typename... T> | ||||
| void print(std::ostream& os, format_string<T...> fmt, T&&... args) { | ||||
|   const auto& vargs = fmt::make_format_args(args...); | ||||
|   if (detail::is_utf8()) | ||||
|     vprint(os, fmt, vargs); | ||||
|   else | ||||
|     detail::vprint_directly(os, fmt, vargs); | ||||
| } | ||||
| 
 | ||||
| FMT_EXPORT | ||||
| template <typename... Args> | ||||
| void print(std::wostream& os, | ||||
|            basic_format_string<wchar_t, type_identity_t<Args>...> fmt, | ||||
|            Args&&... args) { | ||||
|   vprint(os, fmt, fmt::make_format_args<buffer_context<wchar_t>>(args...)); | ||||
|   fmt::vargs<T...> vargs = {{args...}}; | ||||
|   if (detail::use_utf8) return vprint(os, fmt.str, vargs); | ||||
|   auto buffer = memory_buffer(); | ||||
|   detail::vformat_to(buffer, fmt.str, vargs); | ||||
|   detail::write_buffer(os, buffer); | ||||
| } | ||||
| 
 | ||||
| FMT_EXPORT template <typename... T> | ||||
|  | @ -196,14 +161,6 @@ void println(std::ostream& os, format_string<T...> fmt, T&&... args) { | |||
|   fmt::print(os, "{}\n", fmt::format(fmt, std::forward<T>(args)...)); | ||||
| } | ||||
| 
 | ||||
| FMT_EXPORT | ||||
| template <typename... Args> | ||||
| void println(std::wostream& os, | ||||
|              basic_format_string<wchar_t, type_identity_t<Args>...> fmt, | ||||
|              Args&&... args) { | ||||
|   print(os, L"{}\n", fmt::format(fmt, std::forward<Args>(args)...)); | ||||
| } | ||||
| 
 | ||||
| FMT_END_NAMESPACE | ||||
| 
 | ||||
| #endif  // FMT_OSTREAM_H_
 | ||||
|  |  | |||
							
								
								
									
										424
									
								
								thirdparty/fmt/include/fmt/printf.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										424
									
								
								thirdparty/fmt/include/fmt/printf.h
									
										
									
									
										vendored
									
									
								
							|  | @ -8,60 +8,78 @@ | |||
| #ifndef FMT_PRINTF_H_ | ||||
| #define FMT_PRINTF_H_ | ||||
| 
 | ||||
| #include <algorithm>  // std::max | ||||
| #include <limits>     // std::numeric_limits | ||||
| #ifndef FMT_MODULE | ||||
| #  include <algorithm>  // std::max
 | ||||
| #  include <limits>     // std::numeric_limits
 | ||||
| #endif | ||||
| 
 | ||||
| #include "format.h" | ||||
| 
 | ||||
| FMT_BEGIN_NAMESPACE | ||||
| FMT_BEGIN_EXPORT | ||||
| 
 | ||||
| template <typename T> struct printf_formatter { printf_formatter() = delete; }; | ||||
| template <typename T> struct printf_formatter { | ||||
|   printf_formatter() = delete; | ||||
| }; | ||||
| 
 | ||||
| template <typename Char> class basic_printf_context { | ||||
|  private: | ||||
|   detail::buffer_appender<Char> out_; | ||||
|   basic_appender<Char> out_; | ||||
|   basic_format_args<basic_printf_context> args_; | ||||
| 
 | ||||
|   static_assert(std::is_same<Char, char>::value || | ||||
|                     std::is_same<Char, wchar_t>::value, | ||||
|                 "Unsupported code unit type."); | ||||
| 
 | ||||
|  public: | ||||
|   using char_type = Char; | ||||
|   using parse_context_type = basic_format_parse_context<Char>; | ||||
|   using parse_context_type = parse_context<Char>; | ||||
|   template <typename T> using formatter_type = printf_formatter<T>; | ||||
|   enum { builtin_types = 1 }; | ||||
| 
 | ||||
|   /**
 | ||||
|     \rst | ||||
|     Constructs a ``printf_context`` object. References to the arguments are | ||||
|     stored in the context object so make sure they have appropriate lifetimes. | ||||
|     \endrst | ||||
|    */ | ||||
|   basic_printf_context(detail::buffer_appender<Char> out, | ||||
|   /// Constructs a `printf_context` object. References to the arguments are
 | ||||
|   /// stored in the context object so make sure they have appropriate lifetimes.
 | ||||
|   basic_printf_context(basic_appender<Char> out, | ||||
|                        basic_format_args<basic_printf_context> args) | ||||
|       : out_(out), args_(args) {} | ||||
| 
 | ||||
|   auto out() -> detail::buffer_appender<Char> { return out_; } | ||||
|   void advance_to(detail::buffer_appender<Char>) {} | ||||
|   auto out() -> basic_appender<Char> { return out_; } | ||||
|   void advance_to(basic_appender<Char>) {} | ||||
| 
 | ||||
|   auto locale() -> detail::locale_ref { return {}; } | ||||
| 
 | ||||
|   auto arg(int id) const -> basic_format_arg<basic_printf_context> { | ||||
|     return args_.get(id); | ||||
|   } | ||||
| 
 | ||||
|   FMT_CONSTEXPR void on_error(const char* message) { | ||||
|     detail::error_handler().on_error(message); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| namespace detail { | ||||
| 
 | ||||
| // Return the result via the out param to workaround gcc bug 77539.
 | ||||
| template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*> | ||||
| FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr& out) -> bool { | ||||
|   for (out = first; out != last; ++out) { | ||||
|     if (*out == value) return true; | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| inline auto find<false, char>(const char* first, const char* last, char value, | ||||
|                               const char*& out) -> bool { | ||||
|   out = | ||||
|       static_cast<const char*>(memchr(first, value, to_unsigned(last - first))); | ||||
|   return out != nullptr; | ||||
| } | ||||
| 
 | ||||
| // Checks if a value fits in int - used to avoid warnings about comparing
 | ||||
| // signed and unsigned integers.
 | ||||
| template <bool IsSigned> struct int_checker { | ||||
|   template <typename T> static auto fits_in_int(T value) -> bool { | ||||
|     unsigned max = max_value<int>(); | ||||
|     unsigned max = to_unsigned(max_value<int>()); | ||||
|     return value <= max; | ||||
|   } | ||||
|   static auto fits_in_int(bool) -> bool { return true; } | ||||
|   inline static auto fits_in_int(bool) -> bool { return true; } | ||||
| }; | ||||
| 
 | ||||
| template <> struct int_checker<true> { | ||||
|  | @ -69,20 +87,20 @@ template <> struct int_checker<true> { | |||
|     return value >= (std::numeric_limits<int>::min)() && | ||||
|            value <= max_value<int>(); | ||||
|   } | ||||
|   static auto fits_in_int(int) -> bool { return true; } | ||||
|   inline static auto fits_in_int(int) -> bool { return true; } | ||||
| }; | ||||
| 
 | ||||
| struct printf_precision_handler { | ||||
|   template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> | ||||
|   auto operator()(T value) -> int { | ||||
|     if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) | ||||
|       throw_format_error("number is too big"); | ||||
|       report_error("number is too big"); | ||||
|     return (std::max)(static_cast<int>(value), 0); | ||||
|   } | ||||
| 
 | ||||
|   template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> | ||||
|   auto operator()(T) -> int { | ||||
|     throw_format_error("precision is not integer"); | ||||
|     report_error("precision is not integer"); | ||||
|     return 0; | ||||
|   } | ||||
| }; | ||||
|  | @ -102,7 +120,9 @@ struct is_zero_int { | |||
| 
 | ||||
| template <typename T> struct make_unsigned_or_bool : std::make_unsigned<T> {}; | ||||
| 
 | ||||
| template <> struct make_unsigned_or_bool<bool> { using type = bool; }; | ||||
| template <> struct make_unsigned_or_bool<bool> { | ||||
|   using type = bool; | ||||
| }; | ||||
| 
 | ||||
| template <typename T, typename Context> class arg_converter { | ||||
|  private: | ||||
|  | @ -125,25 +145,19 @@ template <typename T, typename Context> class arg_converter { | |||
|     using target_type = conditional_t<std::is_same<T, void>::value, U, T>; | ||||
|     if (const_check(sizeof(target_type) <= sizeof(int))) { | ||||
|       // Extra casts are used to silence warnings.
 | ||||
|       if (is_signed) { | ||||
|         auto n = static_cast<int>(static_cast<target_type>(value)); | ||||
|         arg_ = detail::make_arg<Context>(n); | ||||
|       } else { | ||||
|         using unsigned_type = typename make_unsigned_or_bool<target_type>::type; | ||||
|         auto n = static_cast<unsigned>(static_cast<unsigned_type>(value)); | ||||
|         arg_ = detail::make_arg<Context>(n); | ||||
|       } | ||||
|       using unsigned_type = typename make_unsigned_or_bool<target_type>::type; | ||||
|       if (is_signed) | ||||
|         arg_ = static_cast<int>(static_cast<target_type>(value)); | ||||
|       else | ||||
|         arg_ = static_cast<unsigned>(static_cast<unsigned_type>(value)); | ||||
|     } else { | ||||
|       if (is_signed) { | ||||
|         // glibc's printf doesn't sign extend arguments of smaller types:
 | ||||
|         //   std::printf("%lld", -42);  // prints "4294967254"
 | ||||
|         // but we don't have to do the same because it's a UB.
 | ||||
|         auto n = static_cast<long long>(value); | ||||
|         arg_ = detail::make_arg<Context>(n); | ||||
|       } else { | ||||
|         auto n = static_cast<typename make_unsigned_or_bool<U>::type>(value); | ||||
|         arg_ = detail::make_arg<Context>(n); | ||||
|       } | ||||
|       // glibc's printf doesn't sign extend arguments of smaller types:
 | ||||
|       //   std::printf("%lld", -42);  // prints "4294967254"
 | ||||
|       // but we don't have to do the same because it's a UB.
 | ||||
|       if (is_signed) | ||||
|         arg_ = static_cast<long long>(value); | ||||
|       else | ||||
|         arg_ = static_cast<typename make_unsigned_or_bool<U>::type>(value); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | @ -157,7 +171,7 @@ template <typename T, typename Context> class arg_converter { | |||
| // unsigned).
 | ||||
| template <typename T, typename Context, typename Char> | ||||
| void convert_arg(basic_format_arg<Context>& arg, Char type) { | ||||
|   visit_format_arg(arg_converter<T, Context>(arg, type), arg); | ||||
|   arg.visit(arg_converter<T, Context>(arg, type)); | ||||
| } | ||||
| 
 | ||||
| // Converts an integer argument to char for printf.
 | ||||
|  | @ -170,8 +184,7 @@ template <typename Context> class char_converter { | |||
| 
 | ||||
|   template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> | ||||
|   void operator()(T value) { | ||||
|     auto c = static_cast<typename Context::char_type>(value); | ||||
|     arg_ = detail::make_arg<Context>(c); | ||||
|     arg_ = static_cast<typename Context::char_type>(value); | ||||
|   } | ||||
| 
 | ||||
|   template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> | ||||
|  | @ -187,28 +200,28 @@ template <typename Char> struct get_cstring { | |||
| 
 | ||||
| // Checks if an argument is a valid printf width specifier and sets
 | ||||
| // left alignment if it is negative.
 | ||||
| template <typename Char> class printf_width_handler { | ||||
| class printf_width_handler { | ||||
|  private: | ||||
|   format_specs<Char>& specs_; | ||||
|   format_specs& specs_; | ||||
| 
 | ||||
|  public: | ||||
|   explicit printf_width_handler(format_specs<Char>& specs) : specs_(specs) {} | ||||
|   inline explicit printf_width_handler(format_specs& specs) : specs_(specs) {} | ||||
| 
 | ||||
|   template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> | ||||
|   auto operator()(T value) -> unsigned { | ||||
|     auto width = static_cast<uint32_or_64_or_128_t<T>>(value); | ||||
|     if (detail::is_negative(value)) { | ||||
|       specs_.align = align::left; | ||||
|       specs_.set_align(align::left); | ||||
|       width = 0 - width; | ||||
|     } | ||||
|     unsigned int_max = max_value<int>(); | ||||
|     if (width > int_max) throw_format_error("number is too big"); | ||||
|     unsigned int_max = to_unsigned(max_value<int>()); | ||||
|     if (width > int_max) report_error("number is too big"); | ||||
|     return static_cast<unsigned>(width); | ||||
|   } | ||||
| 
 | ||||
|   template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> | ||||
|   auto operator()(T) -> unsigned { | ||||
|     throw_format_error("width is not integer"); | ||||
|     report_error("width is not integer"); | ||||
|     return 0; | ||||
|   } | ||||
| }; | ||||
|  | @ -216,12 +229,12 @@ template <typename Char> class printf_width_handler { | |||
| // Workaround for a bug with the XL compiler when initializing
 | ||||
| // printf_arg_formatter's base class.
 | ||||
| template <typename Char> | ||||
| auto make_arg_formatter(buffer_appender<Char> iter, format_specs<Char>& s) | ||||
| auto make_arg_formatter(basic_appender<Char> iter, format_specs& s) | ||||
|     -> arg_formatter<Char> { | ||||
|   return {iter, s, locale_ref()}; | ||||
| } | ||||
| 
 | ||||
| // The ``printf`` argument formatter.
 | ||||
| // The `printf` argument formatter.
 | ||||
| template <typename Char> | ||||
| class printf_arg_formatter : public arg_formatter<Char> { | ||||
|  private: | ||||
|  | @ -232,105 +245,96 @@ class printf_arg_formatter : public arg_formatter<Char> { | |||
| 
 | ||||
|   void write_null_pointer(bool is_string = false) { | ||||
|     auto s = this->specs; | ||||
|     s.type = presentation_type::none; | ||||
|     write_bytes(this->out, is_string ? "(null)" : "(nil)", s); | ||||
|     s.set_type(presentation_type::none); | ||||
|     write_bytes<Char>(this->out, is_string ? "(null)" : "(nil)", s); | ||||
|   } | ||||
| 
 | ||||
|   template <typename T> void write(T value) { | ||||
|     detail::write<Char>(this->out, value, this->specs, this->locale); | ||||
|   } | ||||
| 
 | ||||
|  public: | ||||
|   printf_arg_formatter(buffer_appender<Char> iter, format_specs<Char>& s, | ||||
|   printf_arg_formatter(basic_appender<Char> iter, format_specs& s, | ||||
|                        context_type& ctx) | ||||
|       : base(make_arg_formatter(iter, s)), context_(ctx) {} | ||||
| 
 | ||||
|   void operator()(monostate value) { base::operator()(value); } | ||||
|   void operator()(monostate value) { write(value); } | ||||
| 
 | ||||
|   template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)> | ||||
|   void operator()(T value) { | ||||
|     // MSVC2013 fails to compile separate overloads for bool and Char so use
 | ||||
|     // std::is_same instead.
 | ||||
|     if (!std::is_same<T, Char>::value) { | ||||
|       base::operator()(value); | ||||
|       write(value); | ||||
|       return; | ||||
|     } | ||||
|     format_specs<Char> fmt_specs = this->specs; | ||||
|     if (fmt_specs.type != presentation_type::none && | ||||
|         fmt_specs.type != presentation_type::chr) { | ||||
|     format_specs s = this->specs; | ||||
|     if (s.type() != presentation_type::none && | ||||
|         s.type() != presentation_type::chr) { | ||||
|       return (*this)(static_cast<int>(value)); | ||||
|     } | ||||
|     fmt_specs.sign = sign::none; | ||||
|     fmt_specs.alt = false; | ||||
|     fmt_specs.fill[0] = ' ';  // Ignore '0' flag for char types.
 | ||||
|     s.set_sign(sign::none); | ||||
|     s.clear_alt(); | ||||
|     s.set_fill(' ');  // Ignore '0' flag for char types.
 | ||||
|     // align::numeric needs to be overwritten here since the '0' flag is
 | ||||
|     // ignored for non-numeric types
 | ||||
|     if (fmt_specs.align == align::none || fmt_specs.align == align::numeric) | ||||
|       fmt_specs.align = align::right; | ||||
|     write<Char>(this->out, static_cast<Char>(value), fmt_specs); | ||||
|     if (s.align() == align::none || s.align() == align::numeric) | ||||
|       s.set_align(align::right); | ||||
|     detail::write<Char>(this->out, static_cast<Char>(value), s); | ||||
|   } | ||||
| 
 | ||||
|   template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)> | ||||
|   void operator()(T value) { | ||||
|     base::operator()(value); | ||||
|     write(value); | ||||
|   } | ||||
| 
 | ||||
|   /** Formats a null-terminated C string. */ | ||||
|   void operator()(const char* value) { | ||||
|     if (value) | ||||
|       base::operator()(value); | ||||
|       write(value); | ||||
|     else | ||||
|       write_null_pointer(this->specs.type != presentation_type::pointer); | ||||
|       write_null_pointer(this->specs.type() != presentation_type::pointer); | ||||
|   } | ||||
| 
 | ||||
|   /** Formats a null-terminated wide C string. */ | ||||
|   void operator()(const wchar_t* value) { | ||||
|     if (value) | ||||
|       base::operator()(value); | ||||
|       write(value); | ||||
|     else | ||||
|       write_null_pointer(this->specs.type != presentation_type::pointer); | ||||
|       write_null_pointer(this->specs.type() != presentation_type::pointer); | ||||
|   } | ||||
| 
 | ||||
|   void operator()(basic_string_view<Char> value) { base::operator()(value); } | ||||
|   void operator()(basic_string_view<Char> value) { write(value); } | ||||
| 
 | ||||
|   /** Formats a pointer. */ | ||||
|   void operator()(const void* value) { | ||||
|     if (value) | ||||
|       base::operator()(value); | ||||
|       write(value); | ||||
|     else | ||||
|       write_null_pointer(); | ||||
|   } | ||||
| 
 | ||||
|   /** Formats an argument of a custom (user-defined) type. */ | ||||
|   void operator()(typename basic_format_arg<context_type>::handle handle) { | ||||
|     auto parse_ctx = basic_format_parse_context<Char>({}); | ||||
|     auto parse_ctx = parse_context<Char>({}); | ||||
|     handle.format(parse_ctx, context_); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename Char> | ||||
| void parse_flags(format_specs<Char>& specs, const Char*& it, const Char* end) { | ||||
| void parse_flags(format_specs& specs, const Char*& it, const Char* end) { | ||||
|   for (; it != end; ++it) { | ||||
|     switch (*it) { | ||||
|     case '-': | ||||
|       specs.align = align::left; | ||||
|       break; | ||||
|     case '+': | ||||
|       specs.sign = sign::plus; | ||||
|       break; | ||||
|     case '0': | ||||
|       specs.fill[0] = '0'; | ||||
|       break; | ||||
|     case '-': specs.set_align(align::left); break; | ||||
|     case '+': specs.set_sign(sign::plus); break; | ||||
|     case '0': specs.set_fill('0'); break; | ||||
|     case ' ': | ||||
|       if (specs.sign != sign::plus) specs.sign = sign::space; | ||||
|       if (specs.sign() != sign::plus) specs.set_sign(sign::space); | ||||
|       break; | ||||
|     case '#': | ||||
|       specs.alt = true; | ||||
|       break; | ||||
|     default: | ||||
|       return; | ||||
|     case '#': specs.set_alt(); break; | ||||
|     default:  return; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| template <typename Char, typename GetArg> | ||||
| auto parse_header(const Char*& it, const Char* end, format_specs<Char>& specs, | ||||
| auto parse_header(const Char*& it, const Char* end, format_specs& specs, | ||||
|                   GetArg get_arg) -> int { | ||||
|   int arg_index = -1; | ||||
|   Char c = *it; | ||||
|  | @ -342,11 +346,11 @@ auto parse_header(const Char*& it, const Char* end, format_specs<Char>& specs, | |||
|       ++it; | ||||
|       arg_index = value != -1 ? value : max_value<int>(); | ||||
|     } else { | ||||
|       if (c == '0') specs.fill[0] = '0'; | ||||
|       if (c == '0') specs.set_fill('0'); | ||||
|       if (value != 0) { | ||||
|         // Nonzero value means that we parsed width and don't need to
 | ||||
|         // parse it or flags again, so return now.
 | ||||
|         if (value == -1) throw_format_error("number is too big"); | ||||
|         if (value == -1) report_error("number is too big"); | ||||
|         specs.width = value; | ||||
|         return arg_index; | ||||
|       } | ||||
|  | @ -357,63 +361,47 @@ auto parse_header(const Char*& it, const Char* end, format_specs<Char>& specs, | |||
|   if (it != end) { | ||||
|     if (*it >= '0' && *it <= '9') { | ||||
|       specs.width = parse_nonnegative_int(it, end, -1); | ||||
|       if (specs.width == -1) throw_format_error("number is too big"); | ||||
|       if (specs.width == -1) report_error("number is too big"); | ||||
|     } else if (*it == '*') { | ||||
|       ++it; | ||||
|       specs.width = static_cast<int>(visit_format_arg( | ||||
|           detail::printf_width_handler<Char>(specs), get_arg(-1))); | ||||
|       specs.width = static_cast<int>( | ||||
|           get_arg(-1).visit(detail::printf_width_handler(specs))); | ||||
|     } | ||||
|   } | ||||
|   return arg_index; | ||||
| } | ||||
| 
 | ||||
| inline auto parse_printf_presentation_type(char c, type t) | ||||
| inline auto parse_printf_presentation_type(char c, type t, bool& upper) | ||||
|     -> presentation_type { | ||||
|   using pt = presentation_type; | ||||
|   constexpr auto integral_set = sint_set | uint_set | bool_set | char_set; | ||||
|   switch (c) { | ||||
|   case 'd': | ||||
|     return in(t, integral_set) ? pt::dec : pt::none; | ||||
|   case 'o': | ||||
|     return in(t, integral_set) ? pt::oct : pt::none; | ||||
|   case 'x': | ||||
|     return in(t, integral_set) ? pt::hex_lower : pt::none; | ||||
|   case 'X': | ||||
|     return in(t, integral_set) ? pt::hex_upper : pt::none; | ||||
|   case 'a': | ||||
|     return in(t, float_set) ? pt::hexfloat_lower : pt::none; | ||||
|   case 'A': | ||||
|     return in(t, float_set) ? pt::hexfloat_upper : pt::none; | ||||
|   case 'e': | ||||
|     return in(t, float_set) ? pt::exp_lower : pt::none; | ||||
|   case 'E': | ||||
|     return in(t, float_set) ? pt::exp_upper : pt::none; | ||||
|   case 'f': | ||||
|     return in(t, float_set) ? pt::fixed_lower : pt::none; | ||||
|   case 'F': | ||||
|     return in(t, float_set) ? pt::fixed_upper : pt::none; | ||||
|   case 'g': | ||||
|     return in(t, float_set) ? pt::general_lower : pt::none; | ||||
|   case 'G': | ||||
|     return in(t, float_set) ? pt::general_upper : pt::none; | ||||
|   case 'c': | ||||
|     return in(t, integral_set) ? pt::chr : pt::none; | ||||
|   case 's': | ||||
|     return in(t, string_set | cstring_set) ? pt::string : pt::none; | ||||
|   case 'p': | ||||
|     return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none; | ||||
|   default: | ||||
|     return pt::none; | ||||
|   case 'd': return in(t, integral_set) ? pt::dec : pt::none; | ||||
|   case 'o': return in(t, integral_set) ? pt::oct : pt::none; | ||||
|   case 'X': upper = true; FMT_FALLTHROUGH; | ||||
|   case 'x': return in(t, integral_set) ? pt::hex : pt::none; | ||||
|   case 'E': upper = true; FMT_FALLTHROUGH; | ||||
|   case 'e': return in(t, float_set) ? pt::exp : pt::none; | ||||
|   case 'F': upper = true; FMT_FALLTHROUGH; | ||||
|   case 'f': return in(t, float_set) ? pt::fixed : pt::none; | ||||
|   case 'G': upper = true; FMT_FALLTHROUGH; | ||||
|   case 'g': return in(t, float_set) ? pt::general : pt::none; | ||||
|   case 'A': upper = true; FMT_FALLTHROUGH; | ||||
|   case 'a': return in(t, float_set) ? pt::hexfloat : pt::none; | ||||
|   case 'c': return in(t, integral_set) ? pt::chr : pt::none; | ||||
|   case 's': return in(t, string_set | cstring_set) ? pt::string : pt::none; | ||||
|   case 'p': return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none; | ||||
|   default:  return pt::none; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| template <typename Char, typename Context> | ||||
| void vprintf(buffer<Char>& buf, basic_string_view<Char> format, | ||||
|              basic_format_args<Context> args) { | ||||
|   using iterator = buffer_appender<Char>; | ||||
|   using iterator = basic_appender<Char>; | ||||
|   auto out = iterator(buf); | ||||
|   auto context = basic_printf_context<Char>(out, args); | ||||
|   auto parse_ctx = basic_format_parse_context<Char>(format); | ||||
|   auto parse_ctx = parse_context<Char>(format); | ||||
| 
 | ||||
|   // Returns the argument with specified index or, if arg_index is -1, the next
 | ||||
|   // argument.
 | ||||
|  | @ -441,12 +429,12 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format, | |||
|     } | ||||
|     write(out, basic_string_view<Char>(start, to_unsigned(it - 1 - start))); | ||||
| 
 | ||||
|     auto specs = format_specs<Char>(); | ||||
|     specs.align = align::right; | ||||
|     auto specs = format_specs(); | ||||
|     specs.set_align(align::right); | ||||
| 
 | ||||
|     // Parse argument index, flags and width.
 | ||||
|     int arg_index = parse_header(it, end, specs, get_arg); | ||||
|     if (arg_index == 0) throw_format_error("argument not found"); | ||||
|     if (arg_index == 0) report_error("argument not found"); | ||||
| 
 | ||||
|     // Parse precision.
 | ||||
|     if (it != end && *it == '.') { | ||||
|  | @ -456,8 +444,8 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format, | |||
|         specs.precision = parse_nonnegative_int(it, end, 0); | ||||
|       } else if (c == '*') { | ||||
|         ++it; | ||||
|         specs.precision = static_cast<int>( | ||||
|             visit_format_arg(printf_precision_handler(), get_arg(-1))); | ||||
|         specs.precision = | ||||
|             static_cast<int>(get_arg(-1).visit(printf_precision_handler())); | ||||
|       } else { | ||||
|         specs.precision = 0; | ||||
|       } | ||||
|  | @ -466,25 +454,26 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format, | |||
|     auto arg = get_arg(arg_index); | ||||
|     // For d, i, o, u, x, and X conversion specifiers, if a precision is
 | ||||
|     // specified, the '0' flag is ignored
 | ||||
|     if (specs.precision >= 0 && arg.is_integral()) { | ||||
|     if (specs.precision >= 0 && is_integral_type(arg.type())) { | ||||
|       // Ignore '0' for non-numeric types or if '-' present.
 | ||||
|       specs.fill[0] = ' '; | ||||
|       specs.set_fill(' '); | ||||
|     } | ||||
|     if (specs.precision >= 0 && arg.type() == type::cstring_type) { | ||||
|       auto str = visit_format_arg(get_cstring<Char>(), arg); | ||||
|       auto str = arg.visit(get_cstring<Char>()); | ||||
|       auto str_end = str + specs.precision; | ||||
|       auto nul = std::find(str, str_end, Char()); | ||||
|       auto sv = basic_string_view<Char>( | ||||
|           str, to_unsigned(nul != str_end ? nul - str : specs.precision)); | ||||
|       arg = make_arg<basic_printf_context<Char>>(sv); | ||||
|       arg = sv; | ||||
|     } | ||||
|     if (specs.alt && visit_format_arg(is_zero_int(), arg)) specs.alt = false; | ||||
|     if (specs.fill[0] == '0') { | ||||
|       if (arg.is_arithmetic() && specs.align != align::left) | ||||
|         specs.align = align::numeric; | ||||
|       else | ||||
|         specs.fill[0] = ' ';  // Ignore '0' flag for non-numeric types or if '-'
 | ||||
|                               // flag is also present.
 | ||||
|     if (specs.alt() && arg.visit(is_zero_int())) specs.clear_alt(); | ||||
|     if (specs.fill_unit<Char>() == '0') { | ||||
|       if (is_arithmetic_type(arg.type()) && specs.align() != align::left) { | ||||
|         specs.set_align(align::numeric); | ||||
|       } else { | ||||
|         // Ignore '0' flag for non-numeric types or if '-' flag is also present.
 | ||||
|         specs.set_fill(' '); | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // Parse length and convert the argument to the required type.
 | ||||
|  | @ -509,47 +498,39 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format, | |||
|         convert_arg<long>(arg, t); | ||||
|       } | ||||
|       break; | ||||
|     case 'j': | ||||
|       convert_arg<intmax_t>(arg, t); | ||||
|       break; | ||||
|     case 'z': | ||||
|       convert_arg<size_t>(arg, t); | ||||
|       break; | ||||
|     case 't': | ||||
|       convert_arg<std::ptrdiff_t>(arg, t); | ||||
|       break; | ||||
|     case 'j': convert_arg<intmax_t>(arg, t); break; | ||||
|     case 'z': convert_arg<size_t>(arg, t); break; | ||||
|     case 't': convert_arg<std::ptrdiff_t>(arg, t); break; | ||||
|     case 'L': | ||||
|       // printf produces garbage when 'L' is omitted for long double, no
 | ||||
|       // need to do the same.
 | ||||
|       break; | ||||
|     default: | ||||
|       --it; | ||||
|       convert_arg<void>(arg, c); | ||||
|     default: --it; convert_arg<void>(arg, c); | ||||
|     } | ||||
| 
 | ||||
|     // Parse type.
 | ||||
|     if (it == end) throw_format_error("invalid format string"); | ||||
|     if (it == end) report_error("invalid format string"); | ||||
|     char type = static_cast<char>(*it++); | ||||
|     if (arg.is_integral()) { | ||||
|     if (is_integral_type(arg.type())) { | ||||
|       // Normalize type.
 | ||||
|       switch (type) { | ||||
|       case 'i': | ||||
|       case 'u': | ||||
|         type = 'd'; | ||||
|         break; | ||||
|       case 'u': type = 'd'; break; | ||||
|       case 'c': | ||||
|         visit_format_arg(char_converter<basic_printf_context<Char>>(arg), arg); | ||||
|         arg.visit(char_converter<basic_printf_context<Char>>(arg)); | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|     specs.type = parse_printf_presentation_type(type, arg.type()); | ||||
|     if (specs.type == presentation_type::none) | ||||
|       throw_format_error("invalid format specifier"); | ||||
|     bool upper = false; | ||||
|     specs.set_type(parse_printf_presentation_type(type, arg.type(), upper)); | ||||
|     if (specs.type() == presentation_type::none) | ||||
|       report_error("invalid format specifier"); | ||||
|     if (upper) specs.set_upper(); | ||||
| 
 | ||||
|     start = it; | ||||
| 
 | ||||
|     // Format argument.
 | ||||
|     visit_format_arg(printf_arg_formatter<Char>(out, specs, context), arg); | ||||
|     arg.visit(printf_arg_formatter<Char>(out, specs, context)); | ||||
|   } | ||||
|   write(out, basic_string_view<Char>(start, to_unsigned(it - start))); | ||||
| } | ||||
|  | @ -561,56 +542,44 @@ using wprintf_context = basic_printf_context<wchar_t>; | |||
| using printf_args = basic_format_args<printf_context>; | ||||
| using wprintf_args = basic_format_args<wprintf_context>; | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Constructs an `~fmt::format_arg_store` object that contains references to | ||||
|   arguments and can be implicitly converted to `~fmt::printf_args`. | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename... T> | ||||
| inline auto make_printf_args(const T&... args) | ||||
|     -> format_arg_store<printf_context, T...> { | ||||
|   return {args...}; | ||||
| /// Constructs an `format_arg_store` object that contains references to
 | ||||
| /// arguments and can be implicitly converted to `printf_args`.
 | ||||
| template <typename Char = char, typename... T> | ||||
| inline auto make_printf_args(T&... args) | ||||
|     -> decltype(fmt::make_format_args<basic_printf_context<Char>>(args...)) { | ||||
|   return fmt::make_format_args<basic_printf_context<Char>>(args...); | ||||
| } | ||||
| 
 | ||||
| // DEPRECATED!
 | ||||
| template <typename... T> | ||||
| inline auto make_wprintf_args(const T&... args) | ||||
|     -> format_arg_store<wprintf_context, T...> { | ||||
|   return {args...}; | ||||
| } | ||||
| template <typename Char> struct vprintf_args { | ||||
|   using type = basic_format_args<basic_printf_context<Char>>; | ||||
| }; | ||||
| 
 | ||||
| template <typename Char> | ||||
| inline auto vsprintf( | ||||
|     basic_string_view<Char> fmt, | ||||
|     basic_format_args<basic_printf_context<type_identity_t<Char>>> args) | ||||
| inline auto vsprintf(basic_string_view<Char> fmt, | ||||
|                      typename vprintf_args<Char>::type args) | ||||
|     -> std::basic_string<Char> { | ||||
|   auto buf = basic_memory_buffer<Char>(); | ||||
|   detail::vprintf(buf, fmt, args); | ||||
|   return to_string(buf); | ||||
|   return {buf.data(), buf.size()}; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Formats arguments and returns the result as a string. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     std::string message = fmt::sprintf("The answer is %d", 42); | ||||
|   \endrst | ||||
| */ | ||||
| template <typename S, typename... T, | ||||
|           typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>> | ||||
|  * Formats `args` according to specifications in `fmt` and returns the result | ||||
|  * as as string. | ||||
|  * | ||||
|  * **Example**: | ||||
|  * | ||||
|  *     std::string message = fmt::sprintf("The answer is %d", 42); | ||||
|  */ | ||||
| template <typename S, typename... T, typename Char = detail::char_t<S>> | ||||
| inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> { | ||||
|   return vsprintf(detail::to_string_view(fmt), | ||||
|                   fmt::make_format_args<basic_printf_context<Char>>(args...)); | ||||
| } | ||||
| 
 | ||||
| template <typename Char> | ||||
| inline auto vfprintf( | ||||
|     std::FILE* f, basic_string_view<Char> fmt, | ||||
|     basic_format_args<basic_printf_context<type_identity_t<Char>>> args) | ||||
|     -> int { | ||||
| inline auto vfprintf(std::FILE* f, basic_string_view<Char> fmt, | ||||
|                      typename vprintf_args<Char>::type args) -> int { | ||||
|   auto buf = basic_memory_buffer<Char>(); | ||||
|   detail::vprintf(buf, fmt, args); | ||||
|   size_t size = buf.size(); | ||||
|  | @ -620,36 +589,33 @@ inline auto vfprintf( | |||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Prints formatted data to the file *f*. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     fmt::fprintf(stderr, "Don't %s!", "panic"); | ||||
|   \endrst | ||||
|  * Formats `args` according to specifications in `fmt` and writes the output | ||||
|  * to `f`. | ||||
|  * | ||||
|  * **Example**: | ||||
|  * | ||||
|  *     fmt::fprintf(stderr, "Don't %s!", "panic"); | ||||
|  */ | ||||
| template <typename S, typename... T, typename Char = char_t<S>> | ||||
| template <typename S, typename... T, typename Char = detail::char_t<S>> | ||||
| inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int { | ||||
|   return vfprintf(f, detail::to_string_view(fmt), | ||||
|                   fmt::make_format_args<basic_printf_context<Char>>(args...)); | ||||
|                   make_printf_args<Char>(args...)); | ||||
| } | ||||
| 
 | ||||
| template <typename Char> | ||||
| FMT_DEPRECATED inline auto vprintf( | ||||
|     basic_string_view<Char> fmt, | ||||
|     basic_format_args<basic_printf_context<type_identity_t<Char>>> args) | ||||
| FMT_DEPRECATED inline auto vprintf(basic_string_view<Char> fmt, | ||||
|                                    typename vprintf_args<Char>::type args) | ||||
|     -> int { | ||||
|   return vfprintf(stdout, fmt, args); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Prints formatted data to ``stdout``. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     fmt::printf("Elapsed time: %.2f seconds", 1.23); | ||||
|   \endrst | ||||
|  * Formats `args` according to specifications in `fmt` and writes the output | ||||
|  * to `stdout`. | ||||
|  * | ||||
|  * **Example**: | ||||
|  * | ||||
|  *   fmt::printf("Elapsed time: %.2f seconds", 1.23); | ||||
|  */ | ||||
| template <typename... T> | ||||
| inline auto printf(string_view fmt, const T&... args) -> int { | ||||
|  | @ -658,7 +624,7 @@ inline auto printf(string_view fmt, const T&... args) -> int { | |||
| template <typename... T> | ||||
| FMT_DEPRECATED inline auto printf(basic_string_view<wchar_t> fmt, | ||||
|                                   const T&... args) -> int { | ||||
|   return vfprintf(stdout, fmt, make_wprintf_args(args...)); | ||||
|   return vfprintf(stdout, fmt, make_printf_args<wchar_t>(args...)); | ||||
| } | ||||
| 
 | ||||
| FMT_END_EXPORT | ||||
|  |  | |||
							
								
								
									
										641
									
								
								thirdparty/fmt/include/fmt/ranges.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										641
									
								
								thirdparty/fmt/include/fmt/ranges.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,78 +1,38 @@ | |||
| // Formatting library for C++ - experimental range support
 | ||||
| // Formatting library for C++ - range and tuple support
 | ||||
| //
 | ||||
| // Copyright (c) 2012 - present, Victor Zverovich
 | ||||
| // Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
 | ||||
| // All rights reserved.
 | ||||
| //
 | ||||
| // For the license information refer to format.h.
 | ||||
| //
 | ||||
| // Copyright (c) 2018 - present, Remotion (Igor Schulz)
 | ||||
| // All Rights Reserved
 | ||||
| // {fmt} support for ranges, containers and types tuple interface.
 | ||||
| 
 | ||||
| #ifndef FMT_RANGES_H_ | ||||
| #define FMT_RANGES_H_ | ||||
| 
 | ||||
| #include <initializer_list> | ||||
| #include <tuple> | ||||
| #include <type_traits> | ||||
| #ifndef FMT_MODULE | ||||
| #  include <initializer_list> | ||||
| #  include <iterator> | ||||
| #  include <string> | ||||
| #  include <tuple> | ||||
| #  include <type_traits> | ||||
| #  include <utility> | ||||
| #endif | ||||
| 
 | ||||
| #include "format.h" | ||||
| 
 | ||||
| FMT_BEGIN_NAMESPACE | ||||
| 
 | ||||
| FMT_EXPORT | ||||
| enum class range_format { disabled, map, set, sequence, string, debug_string }; | ||||
| 
 | ||||
| namespace detail { | ||||
| 
 | ||||
| template <typename Range, typename OutputIt> | ||||
| auto copy(const Range& range, OutputIt out) -> OutputIt { | ||||
|   for (auto it = range.begin(), end = range.end(); it != end; ++it) | ||||
|     *out++ = *it; | ||||
|   return out; | ||||
| } | ||||
| 
 | ||||
| template <typename OutputIt> | ||||
| auto copy(const char* str, OutputIt out) -> OutputIt { | ||||
|   while (*str) *out++ = *str++; | ||||
|   return out; | ||||
| } | ||||
| 
 | ||||
| template <typename OutputIt> auto copy(char ch, OutputIt out) -> OutputIt { | ||||
|   *out++ = ch; | ||||
|   return out; | ||||
| } | ||||
| 
 | ||||
| template <typename OutputIt> auto copy(wchar_t ch, OutputIt out) -> OutputIt { | ||||
|   *out++ = ch; | ||||
|   return out; | ||||
| } | ||||
| 
 | ||||
| // Returns true if T has a std::string-like interface, like std::string_view.
 | ||||
| template <typename T> class is_std_string_like { | ||||
|   template <typename U> | ||||
|   static auto check(U* p) | ||||
|       -> decltype((void)p->find('a'), p->length(), (void)p->data(), int()); | ||||
|   template <typename> static void check(...); | ||||
| 
 | ||||
|  public: | ||||
|   static constexpr const bool value = | ||||
|       is_string<T>::value || | ||||
|       std::is_convertible<T, std_string_view<char>>::value || | ||||
|       !std::is_void<decltype(check<T>(nullptr))>::value; | ||||
| }; | ||||
| 
 | ||||
| template <typename Char> | ||||
| struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {}; | ||||
| 
 | ||||
| template <typename T> class is_map { | ||||
|   template <typename U> static auto check(U*) -> typename U::mapped_type; | ||||
|   template <typename> static void check(...); | ||||
| 
 | ||||
|  public: | ||||
| #ifdef FMT_FORMAT_MAP_AS_LIST  // DEPRECATED!
 | ||||
|   static constexpr const bool value = false; | ||||
| #else | ||||
|   static constexpr const bool value = | ||||
|       !std::is_void<decltype(check<T>(nullptr))>::value; | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| template <typename T> class is_set { | ||||
|  | @ -80,26 +40,10 @@ template <typename T> class is_set { | |||
|   template <typename> static void check(...); | ||||
| 
 | ||||
|  public: | ||||
| #ifdef FMT_FORMAT_SET_AS_LIST  // DEPRECATED!
 | ||||
|   static constexpr const bool value = false; | ||||
| #else | ||||
|   static constexpr const bool value = | ||||
|       !std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value; | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| template <typename... Ts> struct conditional_helper {}; | ||||
| 
 | ||||
| template <typename T, typename _ = void> struct is_range_ : std::false_type {}; | ||||
| 
 | ||||
| #if !FMT_MSC_VERSION || FMT_MSC_VERSION > 1800 | ||||
| 
 | ||||
| #  define FMT_DECLTYPE_RETURN(val)  \ | ||||
|     ->decltype(val) { return val; } \ | ||||
|     static_assert(                  \ | ||||
|         true, "")  // This makes it so that a semicolon is required after the
 | ||||
|                    // macro, which helps clang-format handle the formatting.
 | ||||
| 
 | ||||
| // C array overload
 | ||||
| template <typename T, std::size_t N> | ||||
| auto range_begin(const T (&arr)[N]) -> const T* { | ||||
|  | @ -114,17 +58,21 @@ template <typename T, typename Enable = void> | |||
| struct has_member_fn_begin_end_t : std::false_type {}; | ||||
| 
 | ||||
| template <typename T> | ||||
| struct has_member_fn_begin_end_t<T, void_t<decltype(std::declval<T>().begin()), | ||||
| struct has_member_fn_begin_end_t<T, void_t<decltype(*std::declval<T>().begin()), | ||||
|                                            decltype(std::declval<T>().end())>> | ||||
|     : std::true_type {}; | ||||
| 
 | ||||
| // Member function overload
 | ||||
| // Member function overloads.
 | ||||
| template <typename T> | ||||
| auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).begin()); | ||||
| auto range_begin(T&& rng) -> decltype(static_cast<T&&>(rng).begin()) { | ||||
|   return static_cast<T&&>(rng).begin(); | ||||
| } | ||||
| template <typename T> | ||||
| auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).end()); | ||||
| auto range_end(T&& rng) -> decltype(static_cast<T&&>(rng).end()) { | ||||
|   return static_cast<T&&>(rng).end(); | ||||
| } | ||||
| 
 | ||||
| // ADL overload. Only participates in overload resolution if member functions
 | ||||
| // ADL overloads. Only participate in overload resolution if member functions
 | ||||
| // are not found.
 | ||||
| template <typename T> | ||||
| auto range_begin(T&& rng) | ||||
|  | @ -145,31 +93,30 @@ struct has_mutable_begin_end : std::false_type {}; | |||
| 
 | ||||
| template <typename T> | ||||
| struct has_const_begin_end< | ||||
|     T, | ||||
|     void_t< | ||||
|         decltype(detail::range_begin(std::declval<const remove_cvref_t<T>&>())), | ||||
|         decltype(detail::range_end(std::declval<const remove_cvref_t<T>&>()))>> | ||||
|     T, void_t<decltype(*detail::range_begin( | ||||
|                   std::declval<const remove_cvref_t<T>&>())), | ||||
|               decltype(detail::range_end( | ||||
|                   std::declval<const remove_cvref_t<T>&>()))>> | ||||
|     : std::true_type {}; | ||||
| 
 | ||||
| template <typename T> | ||||
| struct has_mutable_begin_end< | ||||
|     T, void_t<decltype(detail::range_begin(std::declval<T>())), | ||||
|               decltype(detail::range_end(std::declval<T>())), | ||||
|     T, void_t<decltype(*detail::range_begin(std::declval<T&>())), | ||||
|               decltype(detail::range_end(std::declval<T&>())), | ||||
|               // the extra int here is because older versions of MSVC don't
 | ||||
|               // SFINAE properly unless there are distinct types
 | ||||
|               int>> : std::true_type {}; | ||||
| 
 | ||||
| template <typename T, typename _ = void> struct is_range_ : std::false_type {}; | ||||
| template <typename T> | ||||
| struct is_range_<T, void> | ||||
|     : std::integral_constant<bool, (has_const_begin_end<T>::value || | ||||
|                                     has_mutable_begin_end<T>::value)> {}; | ||||
| #  undef FMT_DECLTYPE_RETURN | ||||
| #endif | ||||
| 
 | ||||
| // tuple_size and tuple_element check.
 | ||||
| template <typename T> class is_tuple_like_ { | ||||
|   template <typename U> | ||||
|   static auto check(U* p) -> decltype(std::tuple_size<U>::value, int()); | ||||
|   template <typename U, typename V = typename std::remove_cv<U>::type> | ||||
|   static auto check(U* p) -> decltype(std::tuple_size<V>::value, 0); | ||||
|   template <typename> static void check(...); | ||||
| 
 | ||||
|  public: | ||||
|  | @ -187,7 +134,7 @@ template <size_t N> using make_index_sequence = std::make_index_sequence<N>; | |||
| template <typename T, T... N> struct integer_sequence { | ||||
|   using value_type = T; | ||||
| 
 | ||||
|   static FMT_CONSTEXPR size_t size() { return sizeof...(N); } | ||||
|   static FMT_CONSTEXPR auto size() -> size_t { return sizeof...(N); } | ||||
| }; | ||||
| 
 | ||||
| template <size_t... N> using index_sequence = integer_sequence<size_t, N...>; | ||||
|  | @ -210,16 +157,17 @@ class is_tuple_formattable_ { | |||
|   static constexpr const bool value = false; | ||||
| }; | ||||
| template <typename T, typename C> class is_tuple_formattable_<T, C, true> { | ||||
|   template <std::size_t... Is> | ||||
|   static std::true_type check2(index_sequence<Is...>, | ||||
|                                integer_sequence<bool, (Is == Is)...>); | ||||
|   static std::false_type check2(...); | ||||
|   template <std::size_t... Is> | ||||
|   static decltype(check2( | ||||
|   template <size_t... Is> | ||||
|   static auto all_true(index_sequence<Is...>, | ||||
|                        integer_sequence<bool, (Is >= 0)...>) -> std::true_type; | ||||
|   static auto all_true(...) -> std::false_type; | ||||
| 
 | ||||
|   template <size_t... Is> | ||||
|   static auto check(index_sequence<Is...>) -> decltype(all_true( | ||||
|       index_sequence<Is...>{}, | ||||
|       integer_sequence< | ||||
|           bool, (is_formattable<typename std::tuple_element<Is, T>::type, | ||||
|                                 C>::value)...>{})) check(index_sequence<Is...>); | ||||
|       integer_sequence<bool, | ||||
|                        (is_formattable<typename std::tuple_element<Is, T>::type, | ||||
|                                        C>::value)...>{})); | ||||
| 
 | ||||
|  public: | ||||
|   static constexpr const bool value = | ||||
|  | @ -296,21 +244,32 @@ FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set) | |||
| template <typename Formatter> | ||||
| FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {} | ||||
| 
 | ||||
| template <typename T> | ||||
| struct range_format_kind_ | ||||
|     : std::integral_constant<range_format, | ||||
|                              std::is_same<uncvref_type<T>, T>::value | ||||
|                                  ? range_format::disabled | ||||
|                              : is_map<T>::value ? range_format::map | ||||
|                              : is_set<T>::value ? range_format::set | ||||
|                                                 : range_format::sequence> {}; | ||||
| 
 | ||||
| template <range_format K> | ||||
| using range_format_constant = std::integral_constant<range_format, K>; | ||||
| 
 | ||||
| // These are not generic lambdas for compatibility with C++11.
 | ||||
| template <typename ParseContext> struct parse_empty_specs { | ||||
| template <typename Char> struct parse_empty_specs { | ||||
|   template <typename Formatter> FMT_CONSTEXPR void operator()(Formatter& f) { | ||||
|     f.parse(ctx); | ||||
|     detail::maybe_set_debug_format(f, true); | ||||
|   } | ||||
|   ParseContext& ctx; | ||||
|   parse_context<Char>& ctx; | ||||
| }; | ||||
| template <typename FormatContext> struct format_tuple_element { | ||||
|   using char_type = typename FormatContext::char_type; | ||||
| 
 | ||||
|   template <typename T> | ||||
|   void operator()(const formatter<T, char_type>& f, const T& v) { | ||||
|     if (i > 0) | ||||
|       ctx.advance_to(detail::copy_str<char_type>(separator, ctx.out())); | ||||
|     if (i > 0) ctx.advance_to(detail::copy<char_type>(separator, ctx.out())); | ||||
|     ctx.advance_to(f.format(v, ctx)); | ||||
|     ++i; | ||||
|   } | ||||
|  | @ -359,68 +318,56 @@ struct formatter<Tuple, Char, | |||
|     closing_bracket_ = close; | ||||
|   } | ||||
| 
 | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { | ||||
|     auto it = ctx.begin(); | ||||
|     if (it != ctx.end() && *it != '}') | ||||
|       FMT_THROW(format_error("invalid format specifier")); | ||||
|     detail::for_each(formatters_, detail::parse_empty_specs<ParseContext>{ctx}); | ||||
|     auto end = ctx.end(); | ||||
|     if (it != end && detail::to_ascii(*it) == 'n') { | ||||
|       ++it; | ||||
|       set_brackets({}, {}); | ||||
|       set_separator({}); | ||||
|     } | ||||
|     if (it != end && *it != '}') report_error("invalid format specifier"); | ||||
|     ctx.advance_to(it); | ||||
|     detail::for_each(formatters_, detail::parse_empty_specs<Char>{ctx}); | ||||
|     return it; | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext> | ||||
|   auto format(const Tuple& value, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     ctx.advance_to(detail::copy_str<Char>(opening_bracket_, ctx.out())); | ||||
|     ctx.advance_to(detail::copy<Char>(opening_bracket_, ctx.out())); | ||||
|     detail::for_each2( | ||||
|         formatters_, value, | ||||
|         detail::format_tuple_element<FormatContext>{0, ctx, separator_}); | ||||
|     return detail::copy_str<Char>(closing_bracket_, ctx.out()); | ||||
|     return detail::copy<Char>(closing_bracket_, ctx.out()); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename T, typename Char> struct is_range { | ||||
|   static constexpr const bool value = | ||||
|       detail::is_range_<T>::value && !detail::is_std_string_like<T>::value && | ||||
|       !std::is_convertible<T, std::basic_string<Char>>::value && | ||||
|       !std::is_convertible<T, detail::std_string_view<Char>>::value; | ||||
|       detail::is_range_<T>::value && !detail::has_to_string_view<T>::value; | ||||
| }; | ||||
| 
 | ||||
| namespace detail { | ||||
| template <typename Context> struct range_mapper { | ||||
|   using mapper = arg_mapper<Context>; | ||||
| 
 | ||||
|   template <typename T, | ||||
|             FMT_ENABLE_IF(has_formatter<remove_cvref_t<T>, Context>::value)> | ||||
|   static auto map(T&& value) -> T&& { | ||||
|     return static_cast<T&&>(value); | ||||
|   } | ||||
|   template <typename T, | ||||
|             FMT_ENABLE_IF(!has_formatter<remove_cvref_t<T>, Context>::value)> | ||||
|   static auto map(T&& value) | ||||
|       -> decltype(mapper().map(static_cast<T&&>(value))) { | ||||
|     return mapper().map(static_cast<T&&>(value)); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename Char, typename Element> | ||||
| using range_formatter_type = | ||||
|     formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map( | ||||
|                   std::declval<Element>()))>, | ||||
|               Char>; | ||||
| using range_formatter_type = formatter<remove_cvref_t<Element>, Char>; | ||||
| 
 | ||||
| template <typename R> | ||||
| using maybe_const_range = | ||||
|     conditional_t<has_const_begin_end<R>::value, const R, R>; | ||||
| 
 | ||||
| // Workaround a bug in MSVC 2015 and earlier.
 | ||||
| #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910 | ||||
| template <typename R, typename Char> | ||||
| struct is_formattable_delayed | ||||
|     : is_formattable<uncvref_type<maybe_const_range<R>>, Char> {}; | ||||
| #endif | ||||
| }  // namespace detail
 | ||||
| 
 | ||||
| template <typename...> struct conjunction : std::true_type {}; | ||||
| template <typename P> struct conjunction<P> : P {}; | ||||
| template <typename P1, typename... Pn> | ||||
| struct conjunction<P1, Pn...> | ||||
|     : conditional_t<bool(P1::value), conjunction<Pn...>, P1> {}; | ||||
| 
 | ||||
| template <typename T, typename Char, typename Enable = void> | ||||
| struct range_formatter; | ||||
| 
 | ||||
|  | @ -436,6 +383,24 @@ struct range_formatter< | |||
|       detail::string_literal<Char, '['>{}; | ||||
|   basic_string_view<Char> closing_bracket_ = | ||||
|       detail::string_literal<Char, ']'>{}; | ||||
|   bool is_debug = false; | ||||
| 
 | ||||
|   template <typename Output, typename It, typename Sentinel, typename U = T, | ||||
|             FMT_ENABLE_IF(std::is_same<U, Char>::value)> | ||||
|   auto write_debug_string(Output& out, It it, Sentinel end) const -> Output { | ||||
|     auto buf = basic_memory_buffer<Char>(); | ||||
|     for (; it != end; ++it) buf.push_back(*it); | ||||
|     auto specs = format_specs(); | ||||
|     specs.set_type(presentation_type::debug); | ||||
|     return detail::write<Char>( | ||||
|         out, basic_string_view<Char>(buf.data(), buf.size()), specs); | ||||
|   } | ||||
| 
 | ||||
|   template <typename Output, typename It, typename Sentinel, typename U = T, | ||||
|             FMT_ENABLE_IF(!std::is_same<U, Char>::value)> | ||||
|   auto write_debug_string(Output& out, It, Sentinel) const -> Output { | ||||
|     return out; | ||||
|   } | ||||
| 
 | ||||
|  public: | ||||
|   FMT_CONSTEXPR range_formatter() {} | ||||
|  | @ -454,21 +419,40 @@ struct range_formatter< | |||
|     closing_bracket_ = close; | ||||
|   } | ||||
| 
 | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { | ||||
|     auto it = ctx.begin(); | ||||
|     auto end = ctx.end(); | ||||
|     detail::maybe_set_debug_format(underlying_, true); | ||||
|     if (it == end) return underlying_.parse(ctx); | ||||
| 
 | ||||
|     if (it != end && *it == 'n') { | ||||
|     switch (detail::to_ascii(*it)) { | ||||
|     case 'n': | ||||
|       set_brackets({}, {}); | ||||
|       ++it; | ||||
|       break; | ||||
|     case '?': | ||||
|       is_debug = true; | ||||
|       set_brackets({}, {}); | ||||
|       ++it; | ||||
|       if (it == end || *it != 's') report_error("invalid format specifier"); | ||||
|       FMT_FALLTHROUGH; | ||||
|     case 's': | ||||
|       if (!std::is_same<T, Char>::value) | ||||
|         report_error("invalid format specifier"); | ||||
|       if (!is_debug) { | ||||
|         set_brackets(detail::string_literal<Char, '"'>{}, | ||||
|                      detail::string_literal<Char, '"'>{}); | ||||
|         set_separator({}); | ||||
|         detail::maybe_set_debug_format(underlying_, false); | ||||
|       } | ||||
|       ++it; | ||||
|       return it; | ||||
|     } | ||||
| 
 | ||||
|     if (it != end && *it != '}') { | ||||
|       if (*it != ':') FMT_THROW(format_error("invalid format specifier")); | ||||
|       if (*it != ':') report_error("invalid format specifier"); | ||||
|       detail::maybe_set_debug_format(underlying_, false); | ||||
|       ++it; | ||||
|     } else { | ||||
|       detail::maybe_set_debug_format(underlying_, true); | ||||
|     } | ||||
| 
 | ||||
|     ctx.advance_to(it); | ||||
|  | @ -477,79 +461,26 @@ struct range_formatter< | |||
| 
 | ||||
|   template <typename R, typename FormatContext> | ||||
|   auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) { | ||||
|     detail::range_mapper<buffer_context<Char>> mapper; | ||||
|     auto out = ctx.out(); | ||||
|     out = detail::copy_str<Char>(opening_bracket_, out); | ||||
|     int i = 0; | ||||
|     auto it = detail::range_begin(range); | ||||
|     auto end = detail::range_end(range); | ||||
|     if (is_debug) return write_debug_string(out, std::move(it), end); | ||||
| 
 | ||||
|     out = detail::copy<Char>(opening_bracket_, out); | ||||
|     int i = 0; | ||||
|     for (; it != end; ++it) { | ||||
|       if (i > 0) out = detail::copy_str<Char>(separator_, out); | ||||
|       if (i > 0) out = detail::copy<Char>(separator_, out); | ||||
|       ctx.advance_to(out); | ||||
|       out = underlying_.format(mapper.map(*it), ctx); | ||||
|       auto&& item = *it;  // Need an lvalue
 | ||||
|       out = underlying_.format(item, ctx); | ||||
|       ++i; | ||||
|     } | ||||
|     out = detail::copy_str<Char>(closing_bracket_, out); | ||||
|     out = detail::copy<Char>(closing_bracket_, out); | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| enum class range_format { disabled, map, set, sequence, string, debug_string }; | ||||
| 
 | ||||
| namespace detail { | ||||
| template <typename T> | ||||
| struct range_format_kind_ | ||||
|     : std::integral_constant<range_format, | ||||
|                              std::is_same<uncvref_type<T>, T>::value | ||||
|                                  ? range_format::disabled | ||||
|                              : is_map<T>::value ? range_format::map | ||||
|                              : is_set<T>::value ? range_format::set | ||||
|                                                 : range_format::sequence> {}; | ||||
| 
 | ||||
| template <range_format K, typename R, typename Char, typename Enable = void> | ||||
| struct range_default_formatter; | ||||
| 
 | ||||
| template <range_format K> | ||||
| using range_format_constant = std::integral_constant<range_format, K>; | ||||
| 
 | ||||
| template <range_format K, typename R, typename Char> | ||||
| struct range_default_formatter< | ||||
|     K, R, Char, | ||||
|     enable_if_t<(K == range_format::sequence || K == range_format::map || | ||||
|                  K == range_format::set)>> { | ||||
|   using range_type = detail::maybe_const_range<R>; | ||||
|   range_formatter<detail::uncvref_type<range_type>, Char> underlying_; | ||||
| 
 | ||||
|   FMT_CONSTEXPR range_default_formatter() { init(range_format_constant<K>()); } | ||||
| 
 | ||||
|   FMT_CONSTEXPR void init(range_format_constant<range_format::set>) { | ||||
|     underlying_.set_brackets(detail::string_literal<Char, '{'>{}, | ||||
|                              detail::string_literal<Char, '}'>{}); | ||||
|   } | ||||
| 
 | ||||
|   FMT_CONSTEXPR void init(range_format_constant<range_format::map>) { | ||||
|     underlying_.set_brackets(detail::string_literal<Char, '{'>{}, | ||||
|                              detail::string_literal<Char, '}'>{}); | ||||
|     underlying_.underlying().set_brackets({}, {}); | ||||
|     underlying_.underlying().set_separator( | ||||
|         detail::string_literal<Char, ':', ' '>{}); | ||||
|   } | ||||
| 
 | ||||
|   FMT_CONSTEXPR void init(range_format_constant<range_format::sequence>) {} | ||||
| 
 | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|     return underlying_.parse(ctx); | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext> | ||||
|   auto format(range_type& range, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     return underlying_.format(range, ctx); | ||||
|   } | ||||
| }; | ||||
| }  // namespace detail
 | ||||
| 
 | ||||
| FMT_EXPORT | ||||
| template <typename T, typename Char, typename Enable = void> | ||||
| struct range_format_kind | ||||
|     : conditional_t< | ||||
|  | @ -559,23 +490,189 @@ struct range_format_kind | |||
| template <typename R, typename Char> | ||||
| struct formatter< | ||||
|     R, Char, | ||||
|     enable_if_t<conjunction<bool_constant<range_format_kind<R, Char>::value != | ||||
|                                           range_format::disabled> | ||||
| // Workaround a bug in MSVC 2015 and earlier.
 | ||||
| #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910 | ||||
|                             , | ||||
|                             detail::is_formattable_delayed<R, Char> | ||||
| #endif | ||||
|                             >::value>> | ||||
|     : detail::range_default_formatter<range_format_kind<R, Char>::value, R, | ||||
|                                       Char> { | ||||
|     enable_if_t<conjunction< | ||||
|         bool_constant< | ||||
|             range_format_kind<R, Char>::value != range_format::disabled && | ||||
|             range_format_kind<R, Char>::value != range_format::map && | ||||
|             range_format_kind<R, Char>::value != range_format::string && | ||||
|             range_format_kind<R, Char>::value != range_format::debug_string>, | ||||
|         detail::is_formattable_delayed<R, Char>>::value>> { | ||||
|  private: | ||||
|   using range_type = detail::maybe_const_range<R>; | ||||
|   range_formatter<detail::uncvref_type<range_type>, Char> range_formatter_; | ||||
| 
 | ||||
|  public: | ||||
|   using nonlocking = void; | ||||
| 
 | ||||
|   FMT_CONSTEXPR formatter() { | ||||
|     if (detail::const_check(range_format_kind<R, Char>::value != | ||||
|                             range_format::set)) | ||||
|       return; | ||||
|     range_formatter_.set_brackets(detail::string_literal<Char, '{'>{}, | ||||
|                                   detail::string_literal<Char, '}'>{}); | ||||
|   } | ||||
| 
 | ||||
|   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { | ||||
|     return range_formatter_.parse(ctx); | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext> | ||||
|   auto format(range_type& range, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     return range_formatter_.format(range, ctx); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename Char, typename... T> struct tuple_join_view : detail::view { | ||||
|   const std::tuple<T...>& tuple; | ||||
| // A map formatter.
 | ||||
| template <typename R, typename Char> | ||||
| struct formatter< | ||||
|     R, Char, | ||||
|     enable_if_t<range_format_kind<R, Char>::value == range_format::map>> { | ||||
|  private: | ||||
|   using map_type = detail::maybe_const_range<R>; | ||||
|   using element_type = detail::uncvref_type<map_type>; | ||||
| 
 | ||||
|   decltype(detail::tuple::get_formatters<element_type, Char>( | ||||
|       detail::tuple_index_sequence<element_type>())) formatters_; | ||||
|   bool no_delimiters_ = false; | ||||
| 
 | ||||
|  public: | ||||
|   FMT_CONSTEXPR formatter() {} | ||||
| 
 | ||||
|   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { | ||||
|     auto it = ctx.begin(); | ||||
|     auto end = ctx.end(); | ||||
|     if (it != end) { | ||||
|       if (detail::to_ascii(*it) == 'n') { | ||||
|         no_delimiters_ = true; | ||||
|         ++it; | ||||
|       } | ||||
|       if (it != end && *it != '}') { | ||||
|         if (*it != ':') report_error("invalid format specifier"); | ||||
|         ++it; | ||||
|       } | ||||
|       ctx.advance_to(it); | ||||
|     } | ||||
|     detail::for_each(formatters_, detail::parse_empty_specs<Char>{ctx}); | ||||
|     return it; | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext> | ||||
|   auto format(map_type& map, FormatContext& ctx) const -> decltype(ctx.out()) { | ||||
|     auto out = ctx.out(); | ||||
|     basic_string_view<Char> open = detail::string_literal<Char, '{'>{}; | ||||
|     if (!no_delimiters_) out = detail::copy<Char>(open, out); | ||||
|     int i = 0; | ||||
|     basic_string_view<Char> sep = detail::string_literal<Char, ',', ' '>{}; | ||||
|     for (auto&& value : map) { | ||||
|       if (i > 0) out = detail::copy<Char>(sep, out); | ||||
|       ctx.advance_to(out); | ||||
|       detail::for_each2(formatters_, value, | ||||
|                         detail::format_tuple_element<FormatContext>{ | ||||
|                             0, ctx, detail::string_literal<Char, ':', ' '>{}}); | ||||
|       ++i; | ||||
|     } | ||||
|     basic_string_view<Char> close = detail::string_literal<Char, '}'>{}; | ||||
|     if (!no_delimiters_) out = detail::copy<Char>(close, out); | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| // A (debug_)string formatter.
 | ||||
| template <typename R, typename Char> | ||||
| struct formatter< | ||||
|     R, Char, | ||||
|     enable_if_t<range_format_kind<R, Char>::value == range_format::string || | ||||
|                 range_format_kind<R, Char>::value == | ||||
|                     range_format::debug_string>> { | ||||
|  private: | ||||
|   using range_type = detail::maybe_const_range<R>; | ||||
|   using string_type = | ||||
|       conditional_t<std::is_constructible< | ||||
|                         detail::std_string_view<Char>, | ||||
|                         decltype(detail::range_begin(std::declval<R>())), | ||||
|                         decltype(detail::range_end(std::declval<R>()))>::value, | ||||
|                     detail::std_string_view<Char>, std::basic_string<Char>>; | ||||
| 
 | ||||
|   formatter<string_type, Char> underlying_; | ||||
| 
 | ||||
|  public: | ||||
|   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { | ||||
|     return underlying_.parse(ctx); | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext> | ||||
|   auto format(range_type& range, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     auto out = ctx.out(); | ||||
|     if (detail::const_check(range_format_kind<R, Char>::value == | ||||
|                             range_format::debug_string)) | ||||
|       *out++ = '"'; | ||||
|     out = underlying_.format( | ||||
|         string_type{detail::range_begin(range), detail::range_end(range)}, ctx); | ||||
|     if (detail::const_check(range_format_kind<R, Char>::value == | ||||
|                             range_format::debug_string)) | ||||
|       *out++ = '"'; | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename It, typename Sentinel, typename Char = char> | ||||
| struct join_view : detail::view { | ||||
|   It begin; | ||||
|   Sentinel end; | ||||
|   basic_string_view<Char> sep; | ||||
| 
 | ||||
|   tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s) | ||||
|   join_view(It b, Sentinel e, basic_string_view<Char> s) | ||||
|       : begin(std::move(b)), end(e), sep(s) {} | ||||
| }; | ||||
| 
 | ||||
| template <typename It, typename Sentinel, typename Char> | ||||
| struct formatter<join_view<It, Sentinel, Char>, Char> { | ||||
|  private: | ||||
|   using value_type = | ||||
| #ifdef __cpp_lib_ranges | ||||
|       std::iter_value_t<It>; | ||||
| #else | ||||
|       typename std::iterator_traits<It>::value_type; | ||||
| #endif | ||||
|   formatter<remove_cvref_t<value_type>, Char> value_formatter_; | ||||
| 
 | ||||
|   using view = conditional_t<std::is_copy_constructible<It>::value, | ||||
|                              const join_view<It, Sentinel, Char>, | ||||
|                              join_view<It, Sentinel, Char>>; | ||||
| 
 | ||||
|  public: | ||||
|   using nonlocking = void; | ||||
| 
 | ||||
|   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { | ||||
|     return value_formatter_.parse(ctx); | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext> | ||||
|   auto format(view& value, FormatContext& ctx) const -> decltype(ctx.out()) { | ||||
|     using iter = | ||||
|         conditional_t<std::is_copy_constructible<view>::value, It, It&>; | ||||
|     iter it = value.begin; | ||||
|     auto out = ctx.out(); | ||||
|     if (it == value.end) return out; | ||||
|     out = value_formatter_.format(*it, ctx); | ||||
|     ++it; | ||||
|     while (it != value.end) { | ||||
|       out = detail::copy<Char>(value.sep.begin(), value.sep.end(), out); | ||||
|       ctx.advance_to(out); | ||||
|       out = value_formatter_.format(*it, ctx); | ||||
|       ++it; | ||||
|     } | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename Char, typename Tuple> struct tuple_join_view : detail::view { | ||||
|   const Tuple& tuple; | ||||
|   basic_string_view<Char> sep; | ||||
| 
 | ||||
|   tuple_join_view(const Tuple& t, basic_string_view<Char> s) | ||||
|       : tuple(t), sep{s} {} | ||||
| }; | ||||
| 
 | ||||
|  | @ -586,65 +683,64 @@ template <typename Char, typename... T> struct tuple_join_view : detail::view { | |||
| #  define FMT_TUPLE_JOIN_SPECIFIERS 0 | ||||
| #endif | ||||
| 
 | ||||
| template <typename Char, typename... T> | ||||
| struct formatter<tuple_join_view<Char, T...>, Char> { | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|     return do_parse(ctx, std::integral_constant<size_t, sizeof...(T)>()); | ||||
| template <typename Char, typename Tuple> | ||||
| struct formatter<tuple_join_view<Char, Tuple>, Char, | ||||
|                  enable_if_t<is_tuple_like<Tuple>::value>> { | ||||
|   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { | ||||
|     return do_parse(ctx, std::tuple_size<Tuple>()); | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext> | ||||
|   auto format(const tuple_join_view<Char, T...>& value, | ||||
|   auto format(const tuple_join_view<Char, Tuple>& value, | ||||
|               FormatContext& ctx) const -> typename FormatContext::iterator { | ||||
|     return do_format(value, ctx, | ||||
|                      std::integral_constant<size_t, sizeof...(T)>()); | ||||
|     return do_format(value, ctx, std::tuple_size<Tuple>()); | ||||
|   } | ||||
| 
 | ||||
|  private: | ||||
|   std::tuple<formatter<typename std::decay<T>::type, Char>...> formatters_; | ||||
|   decltype(detail::tuple::get_formatters<Tuple, Char>( | ||||
|       detail::tuple_index_sequence<Tuple>())) formatters_; | ||||
| 
 | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto do_parse(ParseContext& ctx, | ||||
|   FMT_CONSTEXPR auto do_parse(parse_context<Char>& ctx, | ||||
|                               std::integral_constant<size_t, 0>) | ||||
|       -> decltype(ctx.begin()) { | ||||
|       -> const Char* { | ||||
|     return ctx.begin(); | ||||
|   } | ||||
| 
 | ||||
|   template <typename ParseContext, size_t N> | ||||
|   FMT_CONSTEXPR auto do_parse(ParseContext& ctx, | ||||
|   template <size_t N> | ||||
|   FMT_CONSTEXPR auto do_parse(parse_context<Char>& ctx, | ||||
|                               std::integral_constant<size_t, N>) | ||||
|       -> decltype(ctx.begin()) { | ||||
|       -> const Char* { | ||||
|     auto end = ctx.begin(); | ||||
| #if FMT_TUPLE_JOIN_SPECIFIERS | ||||
|     end = std::get<sizeof...(T) - N>(formatters_).parse(ctx); | ||||
|     end = std::get<std::tuple_size<Tuple>::value - N>(formatters_).parse(ctx); | ||||
|     if (N > 1) { | ||||
|       auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>()); | ||||
|       if (end != end1) | ||||
|         FMT_THROW(format_error("incompatible format specs for tuple elements")); | ||||
|         report_error("incompatible format specs for tuple elements"); | ||||
|     } | ||||
| #endif | ||||
|     return end; | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext> | ||||
|   auto do_format(const tuple_join_view<Char, T...>&, FormatContext& ctx, | ||||
|   auto do_format(const tuple_join_view<Char, Tuple>&, FormatContext& ctx, | ||||
|                  std::integral_constant<size_t, 0>) const -> | ||||
|       typename FormatContext::iterator { | ||||
|     return ctx.out(); | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext, size_t N> | ||||
|   auto do_format(const tuple_join_view<Char, T...>& value, FormatContext& ctx, | ||||
|   auto do_format(const tuple_join_view<Char, Tuple>& value, FormatContext& ctx, | ||||
|                  std::integral_constant<size_t, N>) const -> | ||||
|       typename FormatContext::iterator { | ||||
|     auto out = std::get<sizeof...(T) - N>(formatters_) | ||||
|                    .format(std::get<sizeof...(T) - N>(value.tuple), ctx); | ||||
|     if (N > 1) { | ||||
|       out = std::copy(value.sep.begin(), value.sep.end(), out); | ||||
|       ctx.advance_to(out); | ||||
|       return do_format(value, ctx, std::integral_constant<size_t, N - 1>()); | ||||
|     } | ||||
|     return out; | ||||
|     using std::get; | ||||
|     auto out = | ||||
|         std::get<std::tuple_size<Tuple>::value - N>(formatters_) | ||||
|             .format(get<std::tuple_size<Tuple>::value - N>(value.tuple), ctx); | ||||
|     if (N <= 1) return out; | ||||
|     out = detail::copy<Char>(value.sep, out); | ||||
|     ctx.advance_to(out); | ||||
|     return do_format(value, ctx, std::integral_constant<size_t, N - 1>()); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
|  | @ -688,40 +784,57 @@ struct formatter< | |||
| 
 | ||||
| FMT_BEGIN_EXPORT | ||||
| 
 | ||||
| /// Returns a view that formats the iterator range `[begin, end)` with elements
 | ||||
| /// separated by `sep`.
 | ||||
| template <typename It, typename Sentinel> | ||||
| auto join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel> { | ||||
|   return {std::move(begin), end, sep}; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Returns an object that formats `tuple` with elements separated by `sep`. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     std::tuple<int, char> t = {1, 'a'}; | ||||
|     fmt::print("{}", fmt::join(t, ", ")); | ||||
|     // Output: "1, a"
 | ||||
|   \endrst | ||||
|  * Returns a view that formats `range` with elements separated by `sep`. | ||||
|  * | ||||
|  * **Example**: | ||||
|  * | ||||
|  *     auto v = std::vector<int>{1, 2, 3}; | ||||
|  *     fmt::print("{}", fmt::join(v, ", ")); | ||||
|  *     // Output: 1, 2, 3
 | ||||
|  * | ||||
|  * `fmt::join` applies passed format specifiers to the range elements: | ||||
|  * | ||||
|  *     fmt::print("{:02}", fmt::join(v, ", ")); | ||||
|  *     // Output: 01, 02, 03
 | ||||
|  */ | ||||
| template <typename... T> | ||||
| FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep) | ||||
|     -> tuple_join_view<char, T...> { | ||||
|   return {tuple, sep}; | ||||
| template <typename Range, FMT_ENABLE_IF(!is_tuple_like<Range>::value)> | ||||
| auto join(Range&& r, string_view sep) | ||||
|     -> join_view<decltype(detail::range_begin(r)), | ||||
|                  decltype(detail::range_end(r))> { | ||||
|   return {detail::range_begin(r), detail::range_end(r), sep}; | ||||
| } | ||||
| 
 | ||||
| template <typename... T> | ||||
| FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, | ||||
|                         basic_string_view<wchar_t> sep) | ||||
|     -> tuple_join_view<wchar_t, T...> { | ||||
| /**
 | ||||
|  * Returns an object that formats `std::tuple` with elements separated by `sep`. | ||||
|  * | ||||
|  * **Example**: | ||||
|  * | ||||
|  *     auto t = std::tuple<int, char>{1, 'a'}; | ||||
|  *     fmt::print("{}", fmt::join(t, ", ")); | ||||
|  *     // Output: 1, a
 | ||||
|  */ | ||||
| template <typename Tuple, FMT_ENABLE_IF(is_tuple_like<Tuple>::value)> | ||||
| FMT_CONSTEXPR auto join(const Tuple& tuple, string_view sep) | ||||
|     -> tuple_join_view<char, Tuple> { | ||||
|   return {tuple, sep}; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Returns an object that formats `initializer_list` with elements separated by | ||||
|   `sep`. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     fmt::print("{}", fmt::join({1, 2, 3}, ", ")); | ||||
|     // Output: "1, 2, 3"
 | ||||
|   \endrst | ||||
|  * Returns an object that formats `std::initializer_list` with elements | ||||
|  * separated by `sep`. | ||||
|  * | ||||
|  * **Example**: | ||||
|  * | ||||
|  *     fmt::print("{}", fmt::join({1, 2, 3}, ", ")); | ||||
|  *     // Output: "1, 2, 3"
 | ||||
|  */ | ||||
| template <typename T> | ||||
| auto join(std::initializer_list<T> list, string_view sep) | ||||
|  |  | |||
							
								
								
									
										592
									
								
								thirdparty/fmt/include/fmt/std.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										592
									
								
								thirdparty/fmt/include/fmt/std.h
									
										
									
									
										vendored
									
									
								
							|  | @ -8,35 +8,49 @@ | |||
| #ifndef FMT_STD_H_ | ||||
| #define FMT_STD_H_ | ||||
| 
 | ||||
| #include <atomic> | ||||
| #include <bitset> | ||||
| #include <cstdlib> | ||||
| #include <exception> | ||||
| #include <memory> | ||||
| #include <thread> | ||||
| #include <type_traits> | ||||
| #include <typeinfo> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "format.h" | ||||
| #include "ostream.h" | ||||
| 
 | ||||
| #ifndef FMT_MODULE | ||||
| #  include <atomic> | ||||
| #  include <bitset> | ||||
| #  include <complex> | ||||
| #  include <cstdlib> | ||||
| #  include <exception> | ||||
| #  include <functional> | ||||
| #  include <memory> | ||||
| #  include <thread> | ||||
| #  include <type_traits> | ||||
| #  include <typeinfo> | ||||
| #  include <utility> | ||||
| #  include <vector> | ||||
| 
 | ||||
| // Check FMT_CPLUSPLUS to suppress a bogus warning in MSVC.
 | ||||
| #  if FMT_CPLUSPLUS >= 201703L | ||||
| #    if FMT_HAS_INCLUDE(<filesystem>) && \ | ||||
|         (!defined(FMT_CPP_LIB_FILESYSTEM) || FMT_CPP_LIB_FILESYSTEM != 0) | ||||
| #      include <filesystem> | ||||
| #    endif | ||||
| #    if FMT_HAS_INCLUDE(<variant>) | ||||
| #      include <variant> | ||||
| #    endif | ||||
| #    if FMT_HAS_INCLUDE(<optional>) | ||||
| #      include <optional> | ||||
| #    endif | ||||
| #  endif | ||||
| // Use > instead of >= in the version check because <source_location> may be
 | ||||
| // available after C++17 but before C++20 is marked as implemented.
 | ||||
| #  if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE(<source_location>) | ||||
| #    include <source_location> | ||||
| #  endif | ||||
| #  if FMT_CPLUSPLUS > 202002L && FMT_HAS_INCLUDE(<expected>) | ||||
| #    include <expected> | ||||
| #  endif | ||||
| #endif  // FMT_MODULE
 | ||||
| 
 | ||||
| #if FMT_HAS_INCLUDE(<version>) | ||||
| #  include <version> | ||||
| #endif | ||||
| // Checking FMT_CPLUSPLUS for warning suppression in MSVC.
 | ||||
| #if FMT_CPLUSPLUS >= 201703L | ||||
| #  if FMT_HAS_INCLUDE(<filesystem>) | ||||
| #    include <filesystem> | ||||
| #  endif | ||||
| #  if FMT_HAS_INCLUDE(<variant>) | ||||
| #    include <variant> | ||||
| #  endif | ||||
| #  if FMT_HAS_INCLUDE(<optional>) | ||||
| #    include <optional> | ||||
| #  endif | ||||
| #endif | ||||
| 
 | ||||
| // GCC 4 does not support FMT_HAS_INCLUDE.
 | ||||
| #if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__) | ||||
|  | @ -48,54 +62,53 @@ | |||
| #  endif | ||||
| #endif | ||||
| 
 | ||||
| // Check if typeid is available.
 | ||||
| #ifndef FMT_USE_TYPEID | ||||
| // __RTTI is for EDG compilers. In MSVC typeid is available without RTTI.
 | ||||
| #  if defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || FMT_MSC_VERSION || \ | ||||
|       defined(__INTEL_RTTI__) || defined(__RTTI) | ||||
| #    define FMT_USE_TYPEID 1 | ||||
| // For older Xcode versions, __cpp_lib_xxx flags are inaccurately defined.
 | ||||
| #ifndef FMT_CPP_LIB_FILESYSTEM | ||||
| #  ifdef __cpp_lib_filesystem | ||||
| #    define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem | ||||
| #  else | ||||
| #    define FMT_USE_TYPEID 0 | ||||
| #    define FMT_CPP_LIB_FILESYSTEM 0 | ||||
| #  endif | ||||
| #endif | ||||
| 
 | ||||
| #ifdef __cpp_lib_filesystem | ||||
| #ifndef FMT_CPP_LIB_VARIANT | ||||
| #  ifdef __cpp_lib_variant | ||||
| #    define FMT_CPP_LIB_VARIANT __cpp_lib_variant | ||||
| #  else | ||||
| #    define FMT_CPP_LIB_VARIANT 0 | ||||
| #  endif | ||||
| #endif | ||||
| 
 | ||||
| #if FMT_CPP_LIB_FILESYSTEM | ||||
| FMT_BEGIN_NAMESPACE | ||||
| 
 | ||||
| namespace detail { | ||||
| 
 | ||||
| template <typename Char> auto get_path_string(const std::filesystem::path& p) { | ||||
|   return p.string<Char>(); | ||||
| template <typename Char, typename PathChar> | ||||
| auto get_path_string(const std::filesystem::path& p, | ||||
|                      const std::basic_string<PathChar>& native) { | ||||
|   if constexpr (std::is_same_v<Char, char> && std::is_same_v<PathChar, wchar_t>) | ||||
|     return to_utf8<wchar_t>(native, to_utf8_error_policy::replace); | ||||
|   else | ||||
|     return p.string<Char>(); | ||||
| } | ||||
| 
 | ||||
| template <typename Char> | ||||
| template <typename Char, typename PathChar> | ||||
| void write_escaped_path(basic_memory_buffer<Char>& quoted, | ||||
|                         const std::filesystem::path& p) { | ||||
|   write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>()); | ||||
| } | ||||
| 
 | ||||
| #  ifdef _WIN32 | ||||
| template <> | ||||
| inline auto get_path_string<char>(const std::filesystem::path& p) { | ||||
|   return to_utf8<wchar_t>(p.native(), to_utf8_error_policy::replace); | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| inline void write_escaped_path<char>(memory_buffer& quoted, | ||||
|                                      const std::filesystem::path& p) { | ||||
|   auto buf = basic_memory_buffer<wchar_t>(); | ||||
|   write_escaped_string<wchar_t>(std::back_inserter(buf), p.native()); | ||||
|   bool valid = to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()}); | ||||
|   FMT_ASSERT(valid, "invalid utf16"); | ||||
| } | ||||
| #  endif  // _WIN32
 | ||||
| 
 | ||||
| template <> | ||||
| inline void write_escaped_path<std::filesystem::path::value_type>( | ||||
|     basic_memory_buffer<std::filesystem::path::value_type>& quoted, | ||||
|     const std::filesystem::path& p) { | ||||
|   write_escaped_string<std::filesystem::path::value_type>( | ||||
|       std::back_inserter(quoted), p.native()); | ||||
|                         const std::filesystem::path& p, | ||||
|                         const std::basic_string<PathChar>& native) { | ||||
|   if constexpr (std::is_same_v<Char, char> && | ||||
|                 std::is_same_v<PathChar, wchar_t>) { | ||||
|     auto buf = basic_memory_buffer<wchar_t>(); | ||||
|     write_escaped_string<wchar_t>(std::back_inserter(buf), native); | ||||
|     bool valid = to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()}); | ||||
|     FMT_ASSERT(valid, "invalid utf16"); | ||||
|   } else if constexpr (std::is_same_v<Char, PathChar>) { | ||||
|     write_escaped_string<std::filesystem::path::value_type>( | ||||
|         std::back_inserter(quoted), native); | ||||
|   } else { | ||||
|     write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>()); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| }  // namespace detail
 | ||||
|  | @ -103,48 +116,98 @@ inline void write_escaped_path<std::filesystem::path::value_type>( | |||
| FMT_EXPORT | ||||
| template <typename Char> struct formatter<std::filesystem::path, Char> { | ||||
|  private: | ||||
|   format_specs<Char> specs_; | ||||
|   format_specs specs_; | ||||
|   detail::arg_ref<Char> width_ref_; | ||||
|   bool debug_ = false; | ||||
|   char path_type_ = 0; | ||||
| 
 | ||||
|  public: | ||||
|   FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; } | ||||
| 
 | ||||
|   template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) { | ||||
|   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) { | ||||
|     auto it = ctx.begin(), end = ctx.end(); | ||||
|     if (it == end) return it; | ||||
| 
 | ||||
|     it = detail::parse_align(it, end, specs_); | ||||
|     if (it == end) return it; | ||||
| 
 | ||||
|     it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); | ||||
|     Char c = *it; | ||||
|     if ((c >= '0' && c <= '9') || c == '{') | ||||
|       it = detail::parse_width(it, end, specs_, width_ref_, ctx); | ||||
|     if (it != end && *it == '?') { | ||||
|       debug_ = true; | ||||
|       ++it; | ||||
|     } | ||||
|     if (it != end && (*it == 'g')) path_type_ = detail::to_ascii(*it++); | ||||
|     return it; | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext> | ||||
|   auto format(const std::filesystem::path& p, FormatContext& ctx) const { | ||||
|     auto specs = specs_; | ||||
|     detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_, | ||||
|                                                        ctx); | ||||
|     auto path_string = | ||||
|         !path_type_ ? p.native() | ||||
|                     : p.generic_string<std::filesystem::path::value_type>(); | ||||
| 
 | ||||
|     detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_, | ||||
|                                 ctx); | ||||
|     if (!debug_) { | ||||
|       auto s = detail::get_path_string<Char>(p); | ||||
|       auto s = detail::get_path_string<Char>(p, path_string); | ||||
|       return detail::write(ctx.out(), basic_string_view<Char>(s), specs); | ||||
|     } | ||||
|     auto quoted = basic_memory_buffer<Char>(); | ||||
|     detail::write_escaped_path(quoted, p); | ||||
|     detail::write_escaped_path(quoted, p, path_string); | ||||
|     return detail::write(ctx.out(), | ||||
|                          basic_string_view<Char>(quoted.data(), quoted.size()), | ||||
|                          specs); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| class path : public std::filesystem::path { | ||||
|  public: | ||||
|   auto display_string() const -> std::string { | ||||
|     const std::filesystem::path& base = *this; | ||||
|     return fmt::format(FMT_STRING("{}"), base); | ||||
|   } | ||||
|   auto system_string() const -> std::string { return string(); } | ||||
| 
 | ||||
|   auto generic_display_string() const -> std::string { | ||||
|     const std::filesystem::path& base = *this; | ||||
|     return fmt::format(FMT_STRING("{:g}"), base); | ||||
|   } | ||||
|   auto generic_system_string() const -> std::string { return generic_string(); } | ||||
| }; | ||||
| 
 | ||||
| FMT_END_NAMESPACE | ||||
| #endif | ||||
| #endif  // FMT_CPP_LIB_FILESYSTEM
 | ||||
| 
 | ||||
| FMT_BEGIN_NAMESPACE | ||||
| FMT_EXPORT | ||||
| template <std::size_t N, typename Char> | ||||
| struct formatter<std::bitset<N>, Char> : nested_formatter<string_view> { | ||||
|  private: | ||||
|   // Functor because C++11 doesn't support generic lambdas.
 | ||||
|   struct writer { | ||||
|     const std::bitset<N>& bs; | ||||
| 
 | ||||
|     template <typename OutputIt> | ||||
|     FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt { | ||||
|       for (auto pos = N; pos > 0; --pos) { | ||||
|         out = detail::write<Char>(out, bs[pos - 1] ? Char('1') : Char('0')); | ||||
|       } | ||||
| 
 | ||||
|       return out; | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|  public: | ||||
|   template <typename FormatContext> | ||||
|   auto format(const std::bitset<N>& bs, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     return write_padded(ctx, writer{bs}); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| FMT_EXPORT | ||||
| template <typename Char> | ||||
| struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {}; | ||||
|  | @ -174,13 +237,13 @@ struct formatter<std::optional<T>, Char, | |||
|   FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {} | ||||
| 
 | ||||
|  public: | ||||
|   template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) { | ||||
|   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) { | ||||
|     maybe_set_debug_format(underlying_, true); | ||||
|     return underlying_.parse(ctx); | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext> | ||||
|   auto format(std::optional<T> const& opt, FormatContext& ctx) const | ||||
|   auto format(const std::optional<T>& opt, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     if (!opt) return detail::write<Char>(ctx.out(), none); | ||||
| 
 | ||||
|  | @ -194,7 +257,81 @@ struct formatter<std::optional<T>, Char, | |||
| FMT_END_NAMESPACE | ||||
| #endif  // __cpp_lib_optional
 | ||||
| 
 | ||||
| #ifdef __cpp_lib_variant | ||||
| #if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT | ||||
| 
 | ||||
| FMT_BEGIN_NAMESPACE | ||||
| namespace detail { | ||||
| 
 | ||||
| template <typename Char, typename OutputIt, typename T> | ||||
| auto write_escaped_alternative(OutputIt out, const T& v) -> OutputIt { | ||||
|   if constexpr (has_to_string_view<T>::value) | ||||
|     return write_escaped_string<Char>(out, detail::to_string_view(v)); | ||||
|   if constexpr (std::is_same_v<T, Char>) return write_escaped_char(out, v); | ||||
|   return write<Char>(out, v); | ||||
| } | ||||
| 
 | ||||
| }  // namespace detail
 | ||||
| 
 | ||||
| FMT_END_NAMESPACE | ||||
| #endif | ||||
| 
 | ||||
| #ifdef __cpp_lib_expected | ||||
| FMT_BEGIN_NAMESPACE | ||||
| 
 | ||||
| FMT_EXPORT | ||||
| template <typename T, typename E, typename Char> | ||||
| struct formatter<std::expected<T, E>, Char, | ||||
|                  std::enable_if_t<(std::is_void<T>::value || | ||||
|                                    is_formattable<T, Char>::value) && | ||||
|                                   is_formattable<E, Char>::value>> { | ||||
|   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { | ||||
|     return ctx.begin(); | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext> | ||||
|   auto format(const std::expected<T, E>& value, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     auto out = ctx.out(); | ||||
| 
 | ||||
|     if (value.has_value()) { | ||||
|       out = detail::write<Char>(out, "expected("); | ||||
|       if constexpr (!std::is_void<T>::value) | ||||
|         out = detail::write_escaped_alternative<Char>(out, *value); | ||||
|     } else { | ||||
|       out = detail::write<Char>(out, "unexpected("); | ||||
|       out = detail::write_escaped_alternative<Char>(out, value.error()); | ||||
|     } | ||||
|     *out++ = ')'; | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
| FMT_END_NAMESPACE | ||||
| #endif  // __cpp_lib_expected
 | ||||
| 
 | ||||
| #ifdef __cpp_lib_source_location | ||||
| FMT_BEGIN_NAMESPACE | ||||
| FMT_EXPORT | ||||
| template <> struct formatter<std::source_location> { | ||||
|   FMT_CONSTEXPR auto parse(parse_context<>& ctx) { return ctx.begin(); } | ||||
| 
 | ||||
|   template <typename FormatContext> | ||||
|   auto format(const std::source_location& loc, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     auto out = ctx.out(); | ||||
|     out = detail::write(out, loc.file_name()); | ||||
|     out = detail::write(out, ':'); | ||||
|     out = detail::write<char>(out, loc.line()); | ||||
|     out = detail::write(out, ':'); | ||||
|     out = detail::write<char>(out, loc.column()); | ||||
|     out = detail::write(out, ": "); | ||||
|     out = detail::write(out, loc.function_name()); | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
| FMT_END_NAMESPACE | ||||
| #endif | ||||
| 
 | ||||
| #if FMT_CPP_LIB_VARIANT | ||||
| FMT_BEGIN_NAMESPACE | ||||
| namespace detail { | ||||
| 
 | ||||
|  | @ -218,16 +355,6 @@ template <typename T, typename C> class is_variant_formattable_ { | |||
|       decltype(check(variant_index_sequence<T>{}))::value; | ||||
| }; | ||||
| 
 | ||||
| template <typename Char, typename OutputIt, typename T> | ||||
| auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt { | ||||
|   if constexpr (is_string<T>::value) | ||||
|     return write_escaped_string<Char>(out, detail::to_string_view(v)); | ||||
|   else if constexpr (std::is_same_v<T, Char>) | ||||
|     return write_escaped_char(out, v); | ||||
|   else | ||||
|     return write<Char>(out, v); | ||||
| } | ||||
| 
 | ||||
| }  // namespace detail
 | ||||
| 
 | ||||
| template <typename T> struct is_variant_like { | ||||
|  | @ -241,8 +368,7 @@ template <typename T, typename C> struct is_variant_formattable { | |||
| 
 | ||||
| FMT_EXPORT | ||||
| template <typename Char> struct formatter<std::monostate, Char> { | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { | ||||
|     return ctx.begin(); | ||||
|   } | ||||
| 
 | ||||
|  | @ -259,8 +385,7 @@ struct formatter< | |||
|     Variant, Char, | ||||
|     std::enable_if_t<std::conjunction_v< | ||||
|         is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> { | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { | ||||
|     return ctx.begin(); | ||||
|   } | ||||
| 
 | ||||
|  | @ -273,7 +398,7 @@ struct formatter< | |||
|     FMT_TRY { | ||||
|       std::visit( | ||||
|           [&](const auto& v) { | ||||
|             out = detail::write_variant_alternative<Char>(out, v); | ||||
|             out = detail::write_escaped_alternative<Char>(out, v); | ||||
|           }, | ||||
|           value); | ||||
|     } | ||||
|  | @ -285,111 +410,164 @@ struct formatter< | |||
|   } | ||||
| }; | ||||
| FMT_END_NAMESPACE | ||||
| #endif  // __cpp_lib_variant
 | ||||
| #endif  // FMT_CPP_LIB_VARIANT
 | ||||
| 
 | ||||
| FMT_BEGIN_NAMESPACE | ||||
| FMT_EXPORT | ||||
| template <typename Char> struct formatter<std::error_code, Char> { | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|     return ctx.begin(); | ||||
| template <> struct formatter<std::error_code> { | ||||
|  private: | ||||
|   format_specs specs_; | ||||
|   detail::arg_ref<char> width_ref_; | ||||
| 
 | ||||
|  public: | ||||
|   FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* { | ||||
|     auto it = ctx.begin(), end = ctx.end(); | ||||
|     if (it == end) return it; | ||||
| 
 | ||||
|     it = detail::parse_align(it, end, specs_); | ||||
|     if (it == end) return it; | ||||
| 
 | ||||
|     char c = *it; | ||||
|     if ((c >= '0' && c <= '9') || c == '{') | ||||
|       it = detail::parse_width(it, end, specs_, width_ref_, ctx); | ||||
|     return it; | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext> | ||||
|   FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     auto out = ctx.out(); | ||||
|     out = detail::write_bytes(out, ec.category().name(), format_specs<Char>()); | ||||
|     out = detail::write<Char>(out, Char(':')); | ||||
|     out = detail::write<Char>(out, ec.value()); | ||||
|     return out; | ||||
|   FMT_CONSTEXPR20 auto format(const std::error_code& ec, | ||||
|                               FormatContext& ctx) const -> decltype(ctx.out()) { | ||||
|     auto specs = specs_; | ||||
|     detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_, | ||||
|                                 ctx); | ||||
|     memory_buffer buf; | ||||
|     buf.append(string_view(ec.category().name())); | ||||
|     buf.push_back(':'); | ||||
|     detail::write<char>(appender(buf), ec.value()); | ||||
|     return detail::write<char>(ctx.out(), string_view(buf.data(), buf.size()), | ||||
|                                specs); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| #if FMT_USE_RTTI | ||||
| namespace detail { | ||||
| 
 | ||||
| template <typename Char, typename OutputIt> | ||||
| auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt { | ||||
| #  ifdef FMT_HAS_ABI_CXA_DEMANGLE | ||||
|   int status = 0; | ||||
|   std::size_t size = 0; | ||||
|   std::unique_ptr<char, void (*)(void*)> demangled_name_ptr( | ||||
|       abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free); | ||||
| 
 | ||||
|   string_view demangled_name_view; | ||||
|   if (demangled_name_ptr) { | ||||
|     demangled_name_view = demangled_name_ptr.get(); | ||||
| 
 | ||||
|     // Normalization of stdlib inline namespace names.
 | ||||
|     // libc++ inline namespaces.
 | ||||
|     //  std::__1::*       -> std::*
 | ||||
|     //  std::__1::__fs::* -> std::*
 | ||||
|     // libstdc++ inline namespaces.
 | ||||
|     //  std::__cxx11::*             -> std::*
 | ||||
|     //  std::filesystem::__cxx11::* -> std::filesystem::*
 | ||||
|     if (demangled_name_view.starts_with("std::")) { | ||||
|       char* begin = demangled_name_ptr.get(); | ||||
|       char* to = begin + 5;  // std::
 | ||||
|       for (char *from = to, *end = begin + demangled_name_view.size(); | ||||
|            from < end;) { | ||||
|         // This is safe, because demangled_name is NUL-terminated.
 | ||||
|         if (from[0] == '_' && from[1] == '_') { | ||||
|           char* next = from + 1; | ||||
|           while (next < end && *next != ':') next++; | ||||
|           if (next[0] == ':' && next[1] == ':') { | ||||
|             from = next + 2; | ||||
|             continue; | ||||
|           } | ||||
|         } | ||||
|         *to++ = *from++; | ||||
|       } | ||||
|       demangled_name_view = {begin, detail::to_unsigned(to - begin)}; | ||||
|     } | ||||
|   } else { | ||||
|     demangled_name_view = string_view(ti.name()); | ||||
|   } | ||||
|   return detail::write_bytes<Char>(out, demangled_name_view); | ||||
| #  elif FMT_MSC_VERSION | ||||
|   const string_view demangled_name(ti.name()); | ||||
|   for (std::size_t i = 0; i < demangled_name.size(); ++i) { | ||||
|     auto sub = demangled_name; | ||||
|     sub.remove_prefix(i); | ||||
|     if (sub.starts_with("enum ")) { | ||||
|       i += 4; | ||||
|       continue; | ||||
|     } | ||||
|     if (sub.starts_with("class ") || sub.starts_with("union ")) { | ||||
|       i += 5; | ||||
|       continue; | ||||
|     } | ||||
|     if (sub.starts_with("struct ")) { | ||||
|       i += 6; | ||||
|       continue; | ||||
|     } | ||||
|     if (*sub.begin() != ' ') *out++ = *sub.begin(); | ||||
|   } | ||||
|   return out; | ||||
| #  else | ||||
|   return detail::write_bytes<Char>(out, string_view(ti.name())); | ||||
| #  endif | ||||
| } | ||||
| 
 | ||||
| }  // namespace detail
 | ||||
| 
 | ||||
| FMT_EXPORT | ||||
| template <typename Char> | ||||
| struct formatter<std::type_info, Char  // DEPRECATED! Mixing code unit types.
 | ||||
|                  > { | ||||
|  public: | ||||
|   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { | ||||
|     return ctx.begin(); | ||||
|   } | ||||
| 
 | ||||
|   template <typename Context> | ||||
|   auto format(const std::type_info& ti, Context& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     return detail::write_demangled_name<Char>(ctx.out(), ti); | ||||
|   } | ||||
| }; | ||||
| #endif | ||||
| 
 | ||||
| FMT_EXPORT | ||||
| template <typename T, typename Char> | ||||
| struct formatter< | ||||
|     T, Char, | ||||
|     T, Char,  // DEPRECATED! Mixing code unit types.
 | ||||
|     typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> { | ||||
|  private: | ||||
|   bool with_typename_ = false; | ||||
| 
 | ||||
|  public: | ||||
|   FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx) | ||||
|       -> decltype(ctx.begin()) { | ||||
|   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { | ||||
|     auto it = ctx.begin(); | ||||
|     auto end = ctx.end(); | ||||
|     if (it == end || *it == '}') return it; | ||||
|     if (*it == 't') { | ||||
|       ++it; | ||||
|       with_typename_ = FMT_USE_TYPEID != 0; | ||||
|       with_typename_ = FMT_USE_RTTI != 0; | ||||
|     } | ||||
|     return it; | ||||
|   } | ||||
| 
 | ||||
|   template <typename OutputIt> | ||||
|   auto format(const std::exception& ex, | ||||
|               basic_format_context<OutputIt, Char>& ctx) const -> OutputIt { | ||||
|     format_specs<Char> spec; | ||||
|   template <typename Context> | ||||
|   auto format(const std::exception& ex, Context& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     auto out = ctx.out(); | ||||
|     if (!with_typename_) | ||||
|       return detail::write_bytes(out, string_view(ex.what()), spec); | ||||
| 
 | ||||
| #if FMT_USE_TYPEID | ||||
|     const std::type_info& ti = typeid(ex); | ||||
| #  ifdef FMT_HAS_ABI_CXA_DEMANGLE | ||||
|     int status = 0; | ||||
|     std::size_t size = 0; | ||||
|     std::unique_ptr<char, decltype(&std::free)> demangled_name_ptr( | ||||
|         abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free); | ||||
| 
 | ||||
|     string_view demangled_name_view; | ||||
|     if (demangled_name_ptr) { | ||||
|       demangled_name_view = demangled_name_ptr.get(); | ||||
| 
 | ||||
|       // Normalization of stdlib inline namespace names.
 | ||||
|       // libc++ inline namespaces.
 | ||||
|       //  std::__1::*       -> std::*
 | ||||
|       //  std::__1::__fs::* -> std::*
 | ||||
|       // libstdc++ inline namespaces.
 | ||||
|       //  std::__cxx11::*             -> std::*
 | ||||
|       //  std::filesystem::__cxx11::* -> std::filesystem::*
 | ||||
|       if (demangled_name_view.starts_with("std::")) { | ||||
|         char* begin = demangled_name_ptr.get(); | ||||
|         char* to = begin + 5;  // std::
 | ||||
|         for (char *from = to, *end = begin + demangled_name_view.size(); | ||||
|              from < end;) { | ||||
|           // This is safe, because demangled_name is NUL-terminated.
 | ||||
|           if (from[0] == '_' && from[1] == '_') { | ||||
|             char* next = from + 1; | ||||
|             while (next < end && *next != ':') next++; | ||||
|             if (next[0] == ':' && next[1] == ':') { | ||||
|               from = next + 2; | ||||
|               continue; | ||||
|             } | ||||
|           } | ||||
|           *to++ = *from++; | ||||
|         } | ||||
|         demangled_name_view = {begin, detail::to_unsigned(to - begin)}; | ||||
|       } | ||||
|     } else { | ||||
|       demangled_name_view = string_view(ti.name()); | ||||
| #if FMT_USE_RTTI | ||||
|     if (with_typename_) { | ||||
|       out = detail::write_demangled_name<Char>(out, typeid(ex)); | ||||
|       *out++ = ':'; | ||||
|       *out++ = ' '; | ||||
|     } | ||||
|     out = detail::write_bytes(out, demangled_name_view, spec); | ||||
| #  elif FMT_MSC_VERSION | ||||
|     string_view demangled_name_view(ti.name()); | ||||
|     if (demangled_name_view.starts_with("class ")) | ||||
|       demangled_name_view.remove_prefix(6); | ||||
|     else if (demangled_name_view.starts_with("struct ")) | ||||
|       demangled_name_view.remove_prefix(7); | ||||
|     out = detail::write_bytes(out, demangled_name_view, spec); | ||||
| #  else | ||||
|     out = detail::write_bytes(out, string_view(ti.name()), spec); | ||||
| #  endif | ||||
|     *out++ = ':'; | ||||
|     *out++ = ' '; | ||||
|     return detail::write_bytes(out, string_view(ex.what()), spec); | ||||
| #endif | ||||
|     return detail::write_bytes<Char>(out, string_view(ex.what())); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
|  | @ -436,6 +614,14 @@ struct formatter<BitRef, Char, | |||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename T, typename Deleter> | ||||
| auto ptr(const std::unique_ptr<T, Deleter>& p) -> const void* { | ||||
|   return p.get(); | ||||
| } | ||||
| template <typename T> auto ptr(const std::shared_ptr<T>& p) -> const void* { | ||||
|   return p.get(); | ||||
| } | ||||
| 
 | ||||
| FMT_EXPORT | ||||
| template <typename T, typename Char> | ||||
| struct formatter<std::atomic<T>, Char, | ||||
|  | @ -451,15 +637,91 @@ struct formatter<std::atomic<T>, Char, | |||
| #ifdef __cpp_lib_atomic_flag_test | ||||
| FMT_EXPORT | ||||
| template <typename Char> | ||||
| struct formatter<std::atomic_flag, Char> | ||||
|     : formatter<bool, Char> { | ||||
| struct formatter<std::atomic_flag, Char> : formatter<bool, Char> { | ||||
|   template <typename FormatContext> | ||||
|   auto format(const std::atomic_flag& v, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     return formatter<bool, Char>::format(v.test(), ctx); | ||||
|   } | ||||
| }; | ||||
| #endif // __cpp_lib_atomic_flag_test
 | ||||
| #endif  // __cpp_lib_atomic_flag_test
 | ||||
| 
 | ||||
| FMT_EXPORT | ||||
| template <typename T, typename Char> struct formatter<std::complex<T>, Char> { | ||||
|  private: | ||||
|   detail::dynamic_format_specs<Char> specs_; | ||||
| 
 | ||||
|   template <typename FormatContext, typename OutputIt> | ||||
|   FMT_CONSTEXPR auto do_format(const std::complex<T>& c, | ||||
|                                detail::dynamic_format_specs<Char>& specs, | ||||
|                                FormatContext& ctx, OutputIt out) const | ||||
|       -> OutputIt { | ||||
|     if (c.real() != 0) { | ||||
|       *out++ = Char('('); | ||||
|       out = detail::write<Char>(out, c.real(), specs, ctx.locale()); | ||||
|       specs.set_sign(sign::plus); | ||||
|       out = detail::write<Char>(out, c.imag(), specs, ctx.locale()); | ||||
|       if (!detail::isfinite(c.imag())) *out++ = Char(' '); | ||||
|       *out++ = Char('i'); | ||||
|       *out++ = Char(')'); | ||||
|       return out; | ||||
|     } | ||||
|     out = detail::write<Char>(out, c.imag(), specs, ctx.locale()); | ||||
|     if (!detail::isfinite(c.imag())) *out++ = Char(' '); | ||||
|     *out++ = Char('i'); | ||||
|     return out; | ||||
|   } | ||||
| 
 | ||||
|  public: | ||||
|   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* { | ||||
|     if (ctx.begin() == ctx.end() || *ctx.begin() == '}') return ctx.begin(); | ||||
|     return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, | ||||
|                               detail::type_constant<T, Char>::value); | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext> | ||||
|   auto format(const std::complex<T>& c, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     auto specs = specs_; | ||||
|     if (specs.dynamic()) { | ||||
|       detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, | ||||
|                                   specs.width_ref, ctx); | ||||
|       detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision, | ||||
|                                   specs.precision_ref, ctx); | ||||
|     } | ||||
| 
 | ||||
|     if (specs.width == 0) return do_format(c, specs, ctx, ctx.out()); | ||||
|     auto buf = basic_memory_buffer<Char>(); | ||||
| 
 | ||||
|     auto outer_specs = format_specs(); | ||||
|     outer_specs.width = specs.width; | ||||
|     auto fill = specs.template fill<Char>(); | ||||
|     if (fill) | ||||
|       outer_specs.set_fill(basic_string_view<Char>(fill, specs.fill_size())); | ||||
|     outer_specs.set_align(specs.align()); | ||||
| 
 | ||||
|     specs.width = 0; | ||||
|     specs.set_fill({}); | ||||
|     specs.set_align(align::none); | ||||
| 
 | ||||
|     do_format(c, specs, ctx, basic_appender<Char>(buf)); | ||||
|     return detail::write<Char>(ctx.out(), | ||||
|                                basic_string_view<Char>(buf.data(), buf.size()), | ||||
|                                outer_specs); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| FMT_EXPORT | ||||
| template <typename T, typename Char> | ||||
| struct formatter<std::reference_wrapper<T>, Char, | ||||
|                  enable_if_t<is_formattable<remove_cvref_t<T>, Char>::value>> | ||||
|     : formatter<remove_cvref_t<T>, Char> { | ||||
|   template <typename FormatContext> | ||||
|   auto format(std::reference_wrapper<T> ref, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     return formatter<remove_cvref_t<T>, Char>::format(ref.get(), ctx); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| FMT_END_NAMESPACE | ||||
| #endif  // FMT_STD_H_
 | ||||
|  |  | |||
							
								
								
									
										282
									
								
								thirdparty/fmt/include/fmt/xchar.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										282
									
								
								thirdparty/fmt/include/fmt/xchar.h
									
										
									
									
										vendored
									
									
								
							|  | @ -8,12 +8,16 @@ | |||
| #ifndef FMT_XCHAR_H_ | ||||
| #define FMT_XCHAR_H_ | ||||
| 
 | ||||
| #include <cwchar> | ||||
| 
 | ||||
| #include "color.h" | ||||
| #include "format.h" | ||||
| #include "ostream.h" | ||||
| #include "ranges.h" | ||||
| 
 | ||||
| #ifndef FMT_STATIC_THOUSANDS_SEPARATOR | ||||
| #  include <locale> | ||||
| #ifndef FMT_MODULE | ||||
| #  include <cwchar> | ||||
| #  if FMT_USE_LOCALE | ||||
| #    include <locale> | ||||
| #  endif | ||||
| #endif | ||||
| 
 | ||||
| FMT_BEGIN_NAMESPACE | ||||
|  | @ -22,10 +26,26 @@ namespace detail { | |||
| template <typename T> | ||||
| using is_exotic_char = bool_constant<!std::is_same<T, char>::value>; | ||||
| 
 | ||||
| inline auto write_loc(std::back_insert_iterator<detail::buffer<wchar_t>> out, | ||||
|                       loc_value value, const format_specs<wchar_t>& specs, | ||||
|                       locale_ref loc) -> bool { | ||||
| #ifndef FMT_STATIC_THOUSANDS_SEPARATOR | ||||
| template <typename S, typename = void> struct format_string_char {}; | ||||
| 
 | ||||
| template <typename S> | ||||
| struct format_string_char< | ||||
|     S, void_t<decltype(sizeof(detail::to_string_view(std::declval<S>())))>> { | ||||
|   using type = char_t<S>; | ||||
| }; | ||||
| 
 | ||||
| template <typename S> | ||||
| struct format_string_char< | ||||
|     S, enable_if_t<std::is_base_of<detail::compile_string, S>::value>> { | ||||
|   using type = typename S::char_type; | ||||
| }; | ||||
| 
 | ||||
| template <typename S> | ||||
| using format_string_char_t = typename format_string_char<S>::type; | ||||
| 
 | ||||
| inline auto write_loc(basic_appender<wchar_t> out, loc_value value, | ||||
|                       const format_specs& specs, locale_ref loc) -> bool { | ||||
| #if FMT_USE_LOCALE | ||||
|   auto& numpunct = | ||||
|       std::use_facet<std::numpunct<wchar_t>>(loc.get<std::locale>()); | ||||
|   auto separator = std::wstring(); | ||||
|  | @ -40,41 +60,79 @@ inline auto write_loc(std::back_insert_iterator<detail::buffer<wchar_t>> out, | |||
| FMT_BEGIN_EXPORT | ||||
| 
 | ||||
| using wstring_view = basic_string_view<wchar_t>; | ||||
| using wformat_parse_context = basic_format_parse_context<wchar_t>; | ||||
| using wformat_context = buffer_context<wchar_t>; | ||||
| using wformat_parse_context = parse_context<wchar_t>; | ||||
| using wformat_context = buffered_context<wchar_t>; | ||||
| using wformat_args = basic_format_args<wformat_context>; | ||||
| using wmemory_buffer = basic_memory_buffer<wchar_t>; | ||||
| 
 | ||||
| #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 | ||||
| // Workaround broken conversion on older gcc.
 | ||||
| template <typename... Args> using wformat_string = wstring_view; | ||||
| inline auto runtime(wstring_view s) -> wstring_view { return s; } | ||||
| #else | ||||
| template <typename... Args> | ||||
| using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>; | ||||
| template <typename Char, typename... T> struct basic_fstring { | ||||
|  private: | ||||
|   basic_string_view<Char> str_; | ||||
| 
 | ||||
|   static constexpr int num_static_named_args = | ||||
|       detail::count_static_named_args<T...>(); | ||||
| 
 | ||||
|   using checker = detail::format_string_checker< | ||||
|       Char, static_cast<int>(sizeof...(T)), num_static_named_args, | ||||
|       num_static_named_args != detail::count_named_args<T...>()>; | ||||
| 
 | ||||
|   using arg_pack = detail::arg_pack<T...>; | ||||
| 
 | ||||
|  public: | ||||
|   using t = basic_fstring; | ||||
| 
 | ||||
|   template <typename S, | ||||
|             FMT_ENABLE_IF( | ||||
|                 std::is_convertible<const S&, basic_string_view<Char>>::value)> | ||||
|   FMT_CONSTEVAL FMT_ALWAYS_INLINE basic_fstring(const S& s) : str_(s) { | ||||
|     if (FMT_USE_CONSTEVAL) | ||||
|       detail::parse_format_string<Char>(s, checker(s, arg_pack())); | ||||
|   } | ||||
|   template <typename S, | ||||
|             FMT_ENABLE_IF(std::is_base_of<detail::compile_string, S>::value&& | ||||
|                               std::is_same<typename S::char_type, Char>::value)> | ||||
|   FMT_ALWAYS_INLINE basic_fstring(const S&) : str_(S()) { | ||||
|     FMT_CONSTEXPR auto sv = basic_string_view<Char>(S()); | ||||
|     FMT_CONSTEXPR int ignore = | ||||
|         (parse_format_string(sv, checker(sv, arg_pack())), 0); | ||||
|     detail::ignore_unused(ignore); | ||||
|   } | ||||
|   basic_fstring(runtime_format_string<Char> fmt) : str_(fmt.str) {} | ||||
| 
 | ||||
|   operator basic_string_view<Char>() const { return str_; } | ||||
|   auto get() const -> basic_string_view<Char> { return str_; } | ||||
| }; | ||||
| 
 | ||||
| template <typename Char, typename... T> | ||||
| using basic_format_string = basic_fstring<Char, T...>; | ||||
| 
 | ||||
| template <typename... T> | ||||
| using wformat_string = typename basic_format_string<wchar_t, T...>::t; | ||||
| inline auto runtime(wstring_view s) -> runtime_format_string<wchar_t> { | ||||
|   return {{s}}; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| template <> struct is_char<wchar_t> : std::true_type {}; | ||||
| template <> struct is_char<detail::char8_type> : std::true_type {}; | ||||
| template <> struct is_char<char16_t> : std::true_type {}; | ||||
| template <> struct is_char<char32_t> : std::true_type {}; | ||||
| 
 | ||||
| #ifdef __cpp_char8_t | ||||
| template <> struct is_char<char8_t> : bool_constant<detail::is_utf8_enabled> {}; | ||||
| #endif | ||||
| 
 | ||||
| template <typename... T> | ||||
| constexpr format_arg_store<wformat_context, T...> make_wformat_args( | ||||
|     const T&... args) { | ||||
|   return {args...}; | ||||
| constexpr auto make_wformat_args(T&... args) | ||||
|     -> decltype(fmt::make_format_args<wformat_context>(args...)) { | ||||
|   return fmt::make_format_args<wformat_context>(args...); | ||||
| } | ||||
| 
 | ||||
| #if !FMT_USE_NONTYPE_TEMPLATE_ARGS | ||||
| inline namespace literals { | ||||
| #if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS | ||||
| constexpr detail::udl_arg<wchar_t> operator"" _a(const wchar_t* s, size_t) { | ||||
| inline auto operator""_a(const wchar_t* s, size_t) -> detail::udl_arg<wchar_t> { | ||||
|   return {s}; | ||||
| } | ||||
| #endif | ||||
| }  // namespace literals
 | ||||
| #endif | ||||
| 
 | ||||
| template <typename It, typename Sentinel> | ||||
| auto join(It begin, Sentinel end, wstring_view sep) | ||||
|  | @ -82,9 +140,9 @@ auto join(It begin, Sentinel end, wstring_view sep) | |||
|   return {begin, end, sep}; | ||||
| } | ||||
| 
 | ||||
| template <typename Range> | ||||
| template <typename Range, FMT_ENABLE_IF(!is_tuple_like<Range>::value)> | ||||
| auto join(Range&& range, wstring_view sep) | ||||
|     -> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>, | ||||
|     -> join_view<decltype(std::begin(range)), decltype(std::end(range)), | ||||
|                  wchar_t> { | ||||
|   return join(std::begin(range), std::end(range), sep); | ||||
| } | ||||
|  | @ -95,13 +153,19 @@ auto join(std::initializer_list<T> list, wstring_view sep) | |||
|   return join(std::begin(list), std::end(list), sep); | ||||
| } | ||||
| 
 | ||||
| template <typename Tuple, FMT_ENABLE_IF(is_tuple_like<Tuple>::value)> | ||||
| auto join(const Tuple& tuple, basic_string_view<wchar_t> sep) | ||||
|     -> tuple_join_view<wchar_t, Tuple> { | ||||
|   return {tuple, sep}; | ||||
| } | ||||
| 
 | ||||
| template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)> | ||||
| auto vformat(basic_string_view<Char> format_str, | ||||
|              basic_format_args<buffer_context<type_identity_t<Char>>> args) | ||||
| auto vformat(basic_string_view<Char> fmt, | ||||
|              typename detail::vformat_args<Char>::type args) | ||||
|     -> std::basic_string<Char> { | ||||
|   auto buf = basic_memory_buffer<Char>(); | ||||
|   detail::vformat_to(buf, format_str, args); | ||||
|   return to_string(buf); | ||||
|   detail::vformat_to(buf, fmt, args); | ||||
|   return {buf.data(), buf.size()}; | ||||
| } | ||||
| 
 | ||||
| template <typename... T> | ||||
|  | @ -109,110 +173,117 @@ auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring { | |||
|   return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...)); | ||||
| } | ||||
| 
 | ||||
| template <typename OutputIt, typename... T> | ||||
| auto format_to(OutputIt out, wformat_string<T...> fmt, T&&... args) | ||||
|     -> OutputIt { | ||||
|   return vformat_to(out, fmt::wstring_view(fmt), | ||||
|                     fmt::make_wformat_args(args...)); | ||||
| } | ||||
| 
 | ||||
| // Pass char_t as a default template parameter instead of using
 | ||||
| // std::basic_string<char_t<S>> to reduce the symbol size.
 | ||||
| template <typename S, typename... T, typename Char = char_t<S>, | ||||
| template <typename S, typename... T, | ||||
|           typename Char = detail::format_string_char_t<S>, | ||||
|           FMT_ENABLE_IF(!std::is_same<Char, char>::value && | ||||
|                         !std::is_same<Char, wchar_t>::value)> | ||||
| auto format(const S& format_str, T&&... args) -> std::basic_string<Char> { | ||||
|   return vformat(detail::to_string_view(format_str), | ||||
|                  fmt::make_format_args<buffer_context<Char>>(args...)); | ||||
| auto format(const S& fmt, T&&... args) -> std::basic_string<Char> { | ||||
|   return vformat(detail::to_string_view(fmt), | ||||
|                  fmt::make_format_args<buffered_context<Char>>(args...)); | ||||
| } | ||||
| 
 | ||||
| template <typename Locale, typename S, typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_locale<Locale>::value&& | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
| inline auto vformat( | ||||
|     const Locale& loc, const S& format_str, | ||||
|     basic_format_args<buffer_context<type_identity_t<Char>>> args) | ||||
| template <typename S, typename Char = detail::format_string_char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)> | ||||
| inline auto vformat(detail::locale_ref loc, const S& fmt, | ||||
|                     typename detail::vformat_args<Char>::type args) | ||||
|     -> std::basic_string<Char> { | ||||
|   return detail::vformat(loc, detail::to_string_view(format_str), args); | ||||
|   auto buf = basic_memory_buffer<Char>(); | ||||
|   detail::vformat_to(buf, detail::to_string_view(fmt), args, | ||||
|                      detail::locale_ref(loc)); | ||||
|   return {buf.data(), buf.size()}; | ||||
| } | ||||
| 
 | ||||
| template <typename Locale, typename S, typename... T, typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_locale<Locale>::value&& | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
| inline auto format(const Locale& loc, const S& format_str, T&&... args) | ||||
| template <typename S, typename... T, | ||||
|           typename Char = detail::format_string_char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)> | ||||
| inline auto format(detail::locale_ref loc, const S& fmt, T&&... args) | ||||
|     -> std::basic_string<Char> { | ||||
|   return detail::vformat(loc, detail::to_string_view(format_str), | ||||
|                          fmt::make_format_args<buffer_context<Char>>(args...)); | ||||
|   return vformat(loc, detail::to_string_view(fmt), | ||||
|                  fmt::make_format_args<buffered_context<Char>>(args...)); | ||||
| } | ||||
| 
 | ||||
| template <typename OutputIt, typename S, typename Char = char_t<S>, | ||||
| template <typename OutputIt, typename S, | ||||
|           typename Char = detail::format_string_char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
| auto vformat_to(OutputIt out, const S& format_str, | ||||
|                 basic_format_args<buffer_context<type_identity_t<Char>>> args) | ||||
|     -> OutputIt { | ||||
| auto vformat_to(OutputIt out, const S& fmt, | ||||
|                 typename detail::vformat_args<Char>::type args) -> OutputIt { | ||||
|   auto&& buf = detail::get_buffer<Char>(out); | ||||
|   detail::vformat_to(buf, detail::to_string_view(format_str), args); | ||||
|   detail::vformat_to(buf, detail::to_string_view(fmt), args); | ||||
|   return detail::get_iterator(buf, out); | ||||
| } | ||||
| 
 | ||||
| template <typename OutputIt, typename S, typename... T, | ||||
|           typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
|           typename Char = detail::format_string_char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value && | ||||
|                         !std::is_same<Char, char>::value && | ||||
|                         !std::is_same<Char, wchar_t>::value)> | ||||
| inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt { | ||||
|   return vformat_to(out, detail::to_string_view(fmt), | ||||
|                     fmt::make_format_args<buffer_context<Char>>(args...)); | ||||
|                     fmt::make_format_args<buffered_context<Char>>(args...)); | ||||
| } | ||||
| 
 | ||||
| template <typename Locale, typename S, typename OutputIt, typename... Args, | ||||
|           typename Char = char_t<S>, | ||||
| template <typename S, typename OutputIt, typename... Args, | ||||
|           typename Char = detail::format_string_char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& | ||||
|                             detail::is_locale<Locale>::value&& | ||||
|                                 detail::is_exotic_char<Char>::value)> | ||||
| inline auto vformat_to( | ||||
|     OutputIt out, const Locale& loc, const S& format_str, | ||||
|     basic_format_args<buffer_context<type_identity_t<Char>>> args) -> OutputIt { | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
| inline auto vformat_to(OutputIt out, detail::locale_ref loc, const S& fmt, | ||||
|                        typename detail::vformat_args<Char>::type args) | ||||
|     -> OutputIt { | ||||
|   auto&& buf = detail::get_buffer<Char>(out); | ||||
|   vformat_to(buf, detail::to_string_view(format_str), args, | ||||
|              detail::locale_ref(loc)); | ||||
|   vformat_to(buf, detail::to_string_view(fmt), args, detail::locale_ref(loc)); | ||||
|   return detail::get_iterator(buf, out); | ||||
| } | ||||
| 
 | ||||
| template < | ||||
|     typename OutputIt, typename Locale, typename S, typename... T, | ||||
|     typename Char = char_t<S>, | ||||
|     bool enable = detail::is_output_iterator<OutputIt, Char>::value&& | ||||
|         detail::is_locale<Locale>::value&& detail::is_exotic_char<Char>::value> | ||||
| inline auto format_to(OutputIt out, const Locale& loc, const S& format_str, | ||||
| template <typename OutputIt, typename S, typename... T, | ||||
|           typename Char = detail::format_string_char_t<S>, | ||||
|           bool enable = detail::is_output_iterator<OutputIt, Char>::value && | ||||
|                         detail::is_exotic_char<Char>::value> | ||||
| inline auto format_to(OutputIt out, detail::locale_ref loc, const S& fmt, | ||||
|                       T&&... args) -> | ||||
|     typename std::enable_if<enable, OutputIt>::type { | ||||
|   return vformat_to(out, loc, detail::to_string_view(format_str), | ||||
|                     fmt::make_format_args<buffer_context<Char>>(args...)); | ||||
|   return vformat_to(out, loc, detail::to_string_view(fmt), | ||||
|                     fmt::make_format_args<buffered_context<Char>>(args...)); | ||||
| } | ||||
| 
 | ||||
| template <typename OutputIt, typename Char, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
| inline auto vformat_to_n( | ||||
|     OutputIt out, size_t n, basic_string_view<Char> format_str, | ||||
|     basic_format_args<buffer_context<type_identity_t<Char>>> args) | ||||
| inline auto vformat_to_n(OutputIt out, size_t n, basic_string_view<Char> fmt, | ||||
|                          typename detail::vformat_args<Char>::type args) | ||||
|     -> format_to_n_result<OutputIt> { | ||||
|   using traits = detail::fixed_buffer_traits; | ||||
|   auto buf = detail::iterator_buffer<OutputIt, Char, traits>(out, n); | ||||
|   detail::vformat_to(buf, format_str, args); | ||||
|   detail::vformat_to(buf, fmt, args); | ||||
|   return {buf.out(), buf.count()}; | ||||
| } | ||||
| 
 | ||||
| template <typename OutputIt, typename S, typename... T, | ||||
|           typename Char = char_t<S>, | ||||
|           typename Char = detail::format_string_char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
| inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args) | ||||
|     -> format_to_n_result<OutputIt> { | ||||
|   return vformat_to_n(out, n, detail::to_string_view(fmt), | ||||
|                       fmt::make_format_args<buffer_context<Char>>(args...)); | ||||
|   return vformat_to_n(out, n, fmt::basic_string_view<Char>(fmt), | ||||
|                       fmt::make_format_args<buffered_context<Char>>(args...)); | ||||
| } | ||||
| 
 | ||||
| template <typename S, typename... T, typename Char = char_t<S>, | ||||
| template <typename S, typename... T, | ||||
|           typename Char = detail::format_string_char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)> | ||||
| inline auto formatted_size(const S& fmt, T&&... args) -> size_t { | ||||
|   auto buf = detail::counting_buffer<Char>(); | ||||
|   detail::vformat_to(buf, detail::to_string_view(fmt), | ||||
|                      fmt::make_format_args<buffer_context<Char>>(args...)); | ||||
|                      fmt::make_format_args<buffered_context<Char>>(args...)); | ||||
|   return buf.count(); | ||||
| } | ||||
| 
 | ||||
|  | @ -246,9 +317,48 @@ template <typename... T> void println(wformat_string<T...> fmt, T&&... args) { | |||
|   return print(L"{}\n", fmt::format(fmt, std::forward<T>(args)...)); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   Converts *value* to ``std::wstring`` using the default format for type *T*. | ||||
|  */ | ||||
| inline auto vformat(const text_style& ts, wstring_view fmt, wformat_args args) | ||||
|     -> std::wstring { | ||||
|   auto buf = wmemory_buffer(); | ||||
|   detail::vformat_to(buf, ts, fmt, args); | ||||
|   return {buf.data(), buf.size()}; | ||||
| } | ||||
| 
 | ||||
| template <typename... T> | ||||
| inline auto format(const text_style& ts, wformat_string<T...> fmt, T&&... args) | ||||
|     -> std::wstring { | ||||
|   return fmt::vformat(ts, fmt, fmt::make_wformat_args(args...)); | ||||
| } | ||||
| 
 | ||||
| template <typename... T> | ||||
| FMT_DEPRECATED void print(std::FILE* f, const text_style& ts, | ||||
|                           wformat_string<T...> fmt, const T&... args) { | ||||
|   vprint(f, ts, fmt, fmt::make_wformat_args(args...)); | ||||
| } | ||||
| 
 | ||||
| template <typename... T> | ||||
| FMT_DEPRECATED void print(const text_style& ts, wformat_string<T...> fmt, | ||||
|                           const T&... args) { | ||||
|   return print(stdout, ts, fmt, args...); | ||||
| } | ||||
| 
 | ||||
| inline void vprint(std::wostream& os, wstring_view fmt, wformat_args args) { | ||||
|   auto buffer = basic_memory_buffer<wchar_t>(); | ||||
|   detail::vformat_to(buffer, fmt, args); | ||||
|   detail::write_buffer(os, buffer); | ||||
| } | ||||
| 
 | ||||
| template <typename... T> | ||||
| void print(std::wostream& os, wformat_string<T...> fmt, T&&... args) { | ||||
|   vprint(os, fmt, fmt::make_format_args<buffered_context<wchar_t>>(args...)); | ||||
| } | ||||
| 
 | ||||
| template <typename... T> | ||||
| void println(std::wostream& os, wformat_string<T...> fmt, T&&... args) { | ||||
|   print(os, L"{}\n", fmt::format(fmt, std::forward<T>(args)...)); | ||||
| } | ||||
| 
 | ||||
| /// Converts `value` to `std::wstring` using the default format for type `T`.
 | ||||
| template <typename T> inline auto to_wstring(const T& value) -> std::wstring { | ||||
|   return format(FMT_STRING(L"{}"), value); | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Eidolon
						Eidolon