Merge branch 'tgpfeiffer-bump-fmtlib-6.0.0' into v1.x
This commit is contained in:
		
						commit
						e89d59995a
					
				@ -1,23 +1,27 @@
 | 
				
			|||||||
Copyright (c) 2012 - 2016, Victor Zverovich
 | 
					Copyright (c) 2012 - present, Victor Zverovich
 | 
				
			||||||
 | 
					
 | 
				
			||||||
All rights reserved.
 | 
					Permission is hereby granted, free of charge, to any person obtaining
 | 
				
			||||||
 | 
					a copy of this software and associated documentation files (the
 | 
				
			||||||
 | 
					"Software"), to deal in the Software without restriction, including
 | 
				
			||||||
 | 
					without limitation the rights to use, copy, modify, merge, publish,
 | 
				
			||||||
 | 
					distribute, sublicense, and/or sell copies of the Software, and to
 | 
				
			||||||
 | 
					permit persons to whom the Software is furnished to do so, subject to
 | 
				
			||||||
 | 
					the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Redistribution and use in source and binary forms, with or without
 | 
					The above copyright notice and this permission notice shall be
 | 
				
			||||||
modification, are permitted provided that the following conditions are met:
 | 
					included in all copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1. Redistributions of source code must retain the above copyright notice, this
 | 
					THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
				
			||||||
   list of conditions and the following disclaimer.
 | 
					EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
				
			||||||
2. Redistributions in binary form must reproduce the above copyright notice,
 | 
					MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | 
				
			||||||
   this list of conditions and the following disclaimer in the documentation
 | 
					NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 | 
				
			||||||
   and/or other materials provided with the distribution.
 | 
					LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 | 
				
			||||||
 | 
					OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 | 
				
			||||||
 | 
					WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 | 
					--- Optional exception to the license ---
 | 
				
			||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
					
 | 
				
			||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
					As an exception, if, as a result of your compiling your source code, portions
 | 
				
			||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 | 
					of this Software are embedded into a machine-executable object form of such
 | 
				
			||||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 | 
					source code, you may redistribute such embedded portions in such object form
 | 
				
			||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | 
					without including the above copyright and permission notices.
 | 
				
			||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 | 
					 | 
				
			||||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
					 | 
				
			||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
					 | 
				
			||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -16,9 +16,181 @@
 | 
				
			|||||||
#include <locale>
 | 
					#include <locale>
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// enable safe chrono durations, unless explicitly disabled
 | 
				
			||||||
 | 
					#ifndef FMT_SAFE_DURATION_CAST
 | 
				
			||||||
 | 
					#  define FMT_SAFE_DURATION_CAST 1
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if FMT_SAFE_DURATION_CAST
 | 
				
			||||||
 | 
					#  include "safe-duration-cast.h"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FMT_BEGIN_NAMESPACE
 | 
					FMT_BEGIN_NAMESPACE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace internal{
 | 
					// Prevents expansion of a preceding token as a function-style macro.
 | 
				
			||||||
 | 
					// Usage: f FMT_NOMACRO()
 | 
				
			||||||
 | 
					#define FMT_NOMACRO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace internal {
 | 
				
			||||||
 | 
					inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
 | 
				
			||||||
 | 
					inline null<> localtime_s(...) { return null<>(); }
 | 
				
			||||||
 | 
					inline null<> gmtime_r(...) { return null<>(); }
 | 
				
			||||||
 | 
					inline null<> gmtime_s(...) { return null<>(); }
 | 
				
			||||||
 | 
					}  // namespace internal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Thread-safe replacement for std::localtime
 | 
				
			||||||
 | 
					inline std::tm localtime(std::time_t time) {
 | 
				
			||||||
 | 
					  struct dispatcher {
 | 
				
			||||||
 | 
					    std::time_t time_;
 | 
				
			||||||
 | 
					    std::tm tm_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dispatcher(std::time_t t) : time_(t) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool run() {
 | 
				
			||||||
 | 
					      using namespace fmt::internal;
 | 
				
			||||||
 | 
					      return handle(localtime_r(&time_, &tm_));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool handle(std::tm* tm) { return tm != nullptr; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool handle(internal::null<>) {
 | 
				
			||||||
 | 
					      using namespace fmt::internal;
 | 
				
			||||||
 | 
					      return fallback(localtime_s(&tm_, &time_));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool fallback(int res) { return res == 0; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !FMT_MSC_VER
 | 
				
			||||||
 | 
					    bool fallback(internal::null<>) {
 | 
				
			||||||
 | 
					      using namespace fmt::internal;
 | 
				
			||||||
 | 
					      std::tm* tm = std::localtime(&time_);
 | 
				
			||||||
 | 
					      if (tm) tm_ = *tm;
 | 
				
			||||||
 | 
					      return tm != nullptr;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  dispatcher lt(time);
 | 
				
			||||||
 | 
					  // Too big time values may be unsupported.
 | 
				
			||||||
 | 
					  if (!lt.run()) FMT_THROW(format_error("time_t value out of range"));
 | 
				
			||||||
 | 
					  return lt.tm_;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Thread-safe replacement for std::gmtime
 | 
				
			||||||
 | 
					inline std::tm gmtime(std::time_t time) {
 | 
				
			||||||
 | 
					  struct dispatcher {
 | 
				
			||||||
 | 
					    std::time_t time_;
 | 
				
			||||||
 | 
					    std::tm tm_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dispatcher(std::time_t t) : time_(t) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool run() {
 | 
				
			||||||
 | 
					      using namespace fmt::internal;
 | 
				
			||||||
 | 
					      return handle(gmtime_r(&time_, &tm_));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool handle(std::tm* tm) { return tm != nullptr; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool handle(internal::null<>) {
 | 
				
			||||||
 | 
					      using namespace fmt::internal;
 | 
				
			||||||
 | 
					      return fallback(gmtime_s(&tm_, &time_));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool fallback(int res) { return res == 0; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if !FMT_MSC_VER
 | 
				
			||||||
 | 
					    bool fallback(internal::null<>) {
 | 
				
			||||||
 | 
					      std::tm* tm = std::gmtime(&time_);
 | 
				
			||||||
 | 
					      if (tm) tm_ = *tm;
 | 
				
			||||||
 | 
					      return tm != nullptr;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  dispatcher gt(time);
 | 
				
			||||||
 | 
					  // Too big time values may be unsupported.
 | 
				
			||||||
 | 
					  if (!gt.run()) FMT_THROW(format_error("time_t value out of range"));
 | 
				
			||||||
 | 
					  return gt.tm_;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace internal {
 | 
				
			||||||
 | 
					inline std::size_t strftime(char* str, std::size_t count, const char* format,
 | 
				
			||||||
 | 
					                            const std::tm* time) {
 | 
				
			||||||
 | 
					  return std::strftime(str, count, format, time);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline std::size_t strftime(wchar_t* str, std::size_t count,
 | 
				
			||||||
 | 
					                            const wchar_t* format, const std::tm* time) {
 | 
				
			||||||
 | 
					  return std::wcsftime(str, count, format, time);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}  // namespace internal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Char> struct formatter<std::tm, Char> {
 | 
				
			||||||
 | 
					  template <typename ParseContext>
 | 
				
			||||||
 | 
					  auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
 | 
				
			||||||
 | 
					    auto it = ctx.begin();
 | 
				
			||||||
 | 
					    if (it != ctx.end() && *it == ':') ++it;
 | 
				
			||||||
 | 
					    auto end = it;
 | 
				
			||||||
 | 
					    while (end != ctx.end() && *end != '}') ++end;
 | 
				
			||||||
 | 
					    tm_format.reserve(internal::to_unsigned(end - it + 1));
 | 
				
			||||||
 | 
					    tm_format.append(it, end);
 | 
				
			||||||
 | 
					    tm_format.push_back('\0');
 | 
				
			||||||
 | 
					    return end;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  template <typename FormatContext>
 | 
				
			||||||
 | 
					  auto format(const std::tm& tm, FormatContext& ctx) -> decltype(ctx.out()) {
 | 
				
			||||||
 | 
					    basic_memory_buffer<Char> buf;
 | 
				
			||||||
 | 
					    std::size_t start = buf.size();
 | 
				
			||||||
 | 
					    for (;;) {
 | 
				
			||||||
 | 
					      std::size_t size = buf.capacity() - start;
 | 
				
			||||||
 | 
					      std::size_t count =
 | 
				
			||||||
 | 
					          internal::strftime(&buf[start], size, &tm_format[0], &tm);
 | 
				
			||||||
 | 
					      if (count != 0) {
 | 
				
			||||||
 | 
					        buf.resize(start + count);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (size >= tm_format.size() * 256) {
 | 
				
			||||||
 | 
					        // If the buffer is 256 times larger than the format string, assume
 | 
				
			||||||
 | 
					        // that `strftime` gives an empty result. There doesn't seem to be a
 | 
				
			||||||
 | 
					        // better way to distinguish the two cases:
 | 
				
			||||||
 | 
					        // https://github.com/fmtlib/fmt/issues/367
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const std::size_t MIN_GROWTH = 10;
 | 
				
			||||||
 | 
					      buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return std::copy(buf.begin(), buf.end(), ctx.out());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  basic_memory_buffer<Char> tm_format;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace internal {
 | 
				
			||||||
 | 
					template <typename Period> FMT_CONSTEXPR const char* get_units() {
 | 
				
			||||||
 | 
					  return nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::atto>() { return "as"; }
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::femto>() { return "fs"; }
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::pico>() { return "ps"; }
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::nano>() { return "ns"; }
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::micro>() { return "µs"; }
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::milli>() { return "ms"; }
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::centi>() { return "cs"; }
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::deci>() { return "ds"; }
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::ratio<1>>() { return "s"; }
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::deca>() { return "das"; }
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::hecto>() { return "hs"; }
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::kilo>() { return "ks"; }
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::mega>() { return "Ms"; }
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::giga>() { return "Gs"; }
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::tera>() { return "Ts"; }
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::peta>() { return "Ps"; }
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::exa>() { return "Es"; }
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::ratio<60>>() {
 | 
				
			||||||
 | 
					  return "m";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					template <> FMT_CONSTEXPR const char* get_units<std::ratio<3600>>() {
 | 
				
			||||||
 | 
					  return "h";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class numeric_system {
 | 
					enum class numeric_system {
 | 
				
			||||||
  standard,
 | 
					  standard,
 | 
				
			||||||
@ -28,8 +200,9 @@ enum class numeric_system {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Parses a put_time-like format string and invokes handler actions.
 | 
					// Parses a put_time-like format string and invokes handler actions.
 | 
				
			||||||
template <typename Char, typename Handler>
 | 
					template <typename Char, typename Handler>
 | 
				
			||||||
FMT_CONSTEXPR const Char *parse_chrono_format(
 | 
					FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
 | 
				
			||||||
    const Char *begin, const Char *end, Handler &&handler) {
 | 
					                                              const Char* end,
 | 
				
			||||||
 | 
					                                              Handler&& handler) {
 | 
				
			||||||
  auto ptr = begin;
 | 
					  auto ptr = begin;
 | 
				
			||||||
  while (ptr != end) {
 | 
					  while (ptr != end) {
 | 
				
			||||||
    auto c = *ptr;
 | 
					    auto c = *ptr;
 | 
				
			||||||
@ -38,11 +211,9 @@ FMT_CONSTEXPR const Char *parse_chrono_format(
 | 
				
			|||||||
      ++ptr;
 | 
					      ++ptr;
 | 
				
			||||||
      continue;
 | 
					      continue;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (begin != ptr)
 | 
					    if (begin != ptr) handler.on_text(begin, ptr);
 | 
				
			||||||
      handler.on_text(begin, ptr);
 | 
					 | 
				
			||||||
    ++ptr;  // consume '%'
 | 
					    ++ptr;  // consume '%'
 | 
				
			||||||
    if (ptr == end)
 | 
					    if (ptr == end) FMT_THROW(format_error("invalid format"));
 | 
				
			||||||
      throw format_error("invalid format");
 | 
					 | 
				
			||||||
    c = *ptr++;
 | 
					    c = *ptr++;
 | 
				
			||||||
    switch (c) {
 | 
					    switch (c) {
 | 
				
			||||||
    case '%':
 | 
					    case '%':
 | 
				
			||||||
@ -119,6 +290,12 @@ FMT_CONSTEXPR const Char *parse_chrono_format(
 | 
				
			|||||||
    case 'p':
 | 
					    case 'p':
 | 
				
			||||||
      handler.on_am_pm();
 | 
					      handler.on_am_pm();
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					    case 'Q':
 | 
				
			||||||
 | 
					      handler.on_duration_value();
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    case 'q':
 | 
				
			||||||
 | 
					      handler.on_duration_unit();
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
    case 'z':
 | 
					    case 'z':
 | 
				
			||||||
      handler.on_utc_offset();
 | 
					      handler.on_utc_offset();
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
@ -127,8 +304,7 @@ FMT_CONSTEXPR const Char *parse_chrono_format(
 | 
				
			|||||||
      break;
 | 
					      break;
 | 
				
			||||||
    // Alternative representation:
 | 
					    // Alternative representation:
 | 
				
			||||||
    case 'E': {
 | 
					    case 'E': {
 | 
				
			||||||
      if (ptr == end)
 | 
					      if (ptr == end) FMT_THROW(format_error("invalid format"));
 | 
				
			||||||
        throw format_error("invalid format");
 | 
					 | 
				
			||||||
      c = *ptr++;
 | 
					      c = *ptr++;
 | 
				
			||||||
      switch (c) {
 | 
					      switch (c) {
 | 
				
			||||||
      case 'c':
 | 
					      case 'c':
 | 
				
			||||||
@ -141,13 +317,12 @@ FMT_CONSTEXPR const Char *parse_chrono_format(
 | 
				
			|||||||
        handler.on_loc_time(numeric_system::alternative);
 | 
					        handler.on_loc_time(numeric_system::alternative);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      default:
 | 
					      default:
 | 
				
			||||||
        throw format_error("invalid format");
 | 
					        FMT_THROW(format_error("invalid format"));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case 'O':
 | 
					    case 'O':
 | 
				
			||||||
      if (ptr == end)
 | 
					      if (ptr == end) FMT_THROW(format_error("invalid format"));
 | 
				
			||||||
        throw format_error("invalid format");
 | 
					 | 
				
			||||||
      c = *ptr++;
 | 
					      c = *ptr++;
 | 
				
			||||||
      switch (c) {
 | 
					      switch (c) {
 | 
				
			||||||
      case 'w':
 | 
					      case 'w':
 | 
				
			||||||
@ -169,96 +344,259 @@ FMT_CONSTEXPR const Char *parse_chrono_format(
 | 
				
			|||||||
        handler.on_second(numeric_system::alternative);
 | 
					        handler.on_second(numeric_system::alternative);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      default:
 | 
					      default:
 | 
				
			||||||
        throw format_error("invalid format");
 | 
					        FMT_THROW(format_error("invalid format"));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
      throw format_error("invalid format");
 | 
					      FMT_THROW(format_error("invalid format"));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    begin = ptr;
 | 
					    begin = ptr;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (begin != ptr)
 | 
					  if (begin != ptr) handler.on_text(begin, ptr);
 | 
				
			||||||
    handler.on_text(begin, ptr);
 | 
					 | 
				
			||||||
  return ptr;
 | 
					  return ptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct chrono_format_checker {
 | 
					struct chrono_format_checker {
 | 
				
			||||||
  void report_no_date() { throw format_error("no date"); }
 | 
					  FMT_NORETURN void report_no_date() { FMT_THROW(format_error("no date")); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template <typename Char>
 | 
					  template <typename Char> void on_text(const Char*, const Char*) {}
 | 
				
			||||||
  void on_text(const Char *, const Char *) {}
 | 
					  FMT_NORETURN void on_abbr_weekday() { report_no_date(); }
 | 
				
			||||||
  void on_abbr_weekday() { report_no_date(); }
 | 
					  FMT_NORETURN void on_full_weekday() { report_no_date(); }
 | 
				
			||||||
  void on_full_weekday() { report_no_date(); }
 | 
					  FMT_NORETURN void on_dec0_weekday(numeric_system) { report_no_date(); }
 | 
				
			||||||
  void on_dec0_weekday(numeric_system) { report_no_date(); }
 | 
					  FMT_NORETURN void on_dec1_weekday(numeric_system) { report_no_date(); }
 | 
				
			||||||
  void on_dec1_weekday(numeric_system) { report_no_date(); }
 | 
					  FMT_NORETURN void on_abbr_month() { report_no_date(); }
 | 
				
			||||||
  void on_abbr_month() { report_no_date(); }
 | 
					  FMT_NORETURN void on_full_month() { report_no_date(); }
 | 
				
			||||||
  void on_full_month() { report_no_date(); }
 | 
					 | 
				
			||||||
  void on_24_hour(numeric_system) {}
 | 
					  void on_24_hour(numeric_system) {}
 | 
				
			||||||
  void on_12_hour(numeric_system) {}
 | 
					  void on_12_hour(numeric_system) {}
 | 
				
			||||||
  void on_minute(numeric_system) {}
 | 
					  void on_minute(numeric_system) {}
 | 
				
			||||||
  void on_second(numeric_system) {}
 | 
					  void on_second(numeric_system) {}
 | 
				
			||||||
  void on_datetime(numeric_system) { report_no_date(); }
 | 
					  FMT_NORETURN void on_datetime(numeric_system) { report_no_date(); }
 | 
				
			||||||
  void on_loc_date(numeric_system) { report_no_date(); }
 | 
					  FMT_NORETURN void on_loc_date(numeric_system) { report_no_date(); }
 | 
				
			||||||
  void on_loc_time(numeric_system) { report_no_date(); }
 | 
					  FMT_NORETURN void on_loc_time(numeric_system) { report_no_date(); }
 | 
				
			||||||
  void on_us_date() { report_no_date(); }
 | 
					  FMT_NORETURN void on_us_date() { report_no_date(); }
 | 
				
			||||||
  void on_iso_date() { report_no_date(); }
 | 
					  FMT_NORETURN void on_iso_date() { report_no_date(); }
 | 
				
			||||||
  void on_12_hour_time() {}
 | 
					  void on_12_hour_time() {}
 | 
				
			||||||
  void on_24_hour_time() {}
 | 
					  void on_24_hour_time() {}
 | 
				
			||||||
  void on_iso_time() {}
 | 
					  void on_iso_time() {}
 | 
				
			||||||
  void on_am_pm() {}
 | 
					  void on_am_pm() {}
 | 
				
			||||||
  void on_utc_offset() { report_no_date(); }
 | 
					  void on_duration_value() {}
 | 
				
			||||||
  void on_tz_name() { report_no_date(); }
 | 
					  void on_duration_unit() {}
 | 
				
			||||||
 | 
					  FMT_NORETURN void on_utc_offset() { report_no_date(); }
 | 
				
			||||||
 | 
					  FMT_NORETURN void on_tz_name() { report_no_date(); }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename Int>
 | 
					template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
 | 
				
			||||||
inline int to_int(Int value) {
 | 
					inline bool isnan(T) {
 | 
				
			||||||
  FMT_ASSERT(value >= (std::numeric_limits<int>::min)() &&
 | 
					  return false;
 | 
				
			||||||
             value <= (std::numeric_limits<int>::max)(), "invalid value");
 | 
					}
 | 
				
			||||||
 | 
					template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
 | 
				
			||||||
 | 
					inline bool isnan(T value) {
 | 
				
			||||||
 | 
					  return std::isnan(value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
 | 
				
			||||||
 | 
					inline bool isfinite(T) {
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
 | 
				
			||||||
 | 
					inline bool isfinite(T value) {
 | 
				
			||||||
 | 
					  return std::isfinite(value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Convers value to int and checks that it's in the range [0, upper).
 | 
				
			||||||
 | 
					template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
 | 
				
			||||||
 | 
					inline int to_nonnegative_int(T value, int upper) {
 | 
				
			||||||
 | 
					  FMT_ASSERT(value >= 0 && value <= upper, "invalid value");
 | 
				
			||||||
 | 
					  (void)upper;
 | 
				
			||||||
 | 
					  return static_cast<int>(value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
 | 
				
			||||||
 | 
					inline int to_nonnegative_int(T value, int upper) {
 | 
				
			||||||
 | 
					  FMT_ASSERT(
 | 
				
			||||||
 | 
					      std::isnan(value) || (value >= 0 && value <= static_cast<T>(upper)),
 | 
				
			||||||
 | 
					      "invalid value");
 | 
				
			||||||
 | 
					  (void)upper;
 | 
				
			||||||
  return static_cast<int>(value);
 | 
					  return static_cast<int>(value);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename FormatContext, typename OutputIt>
 | 
					template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
 | 
				
			||||||
 | 
					inline T mod(T x, int y) {
 | 
				
			||||||
 | 
					  return x % y;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
 | 
				
			||||||
 | 
					inline T mod(T x, int y) {
 | 
				
			||||||
 | 
					  return std::fmod(x, static_cast<T>(y));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// If T is an integral type, maps T to its unsigned counterpart, otherwise
 | 
				
			||||||
 | 
					// leaves it unchanged (unlike std::make_unsigned).
 | 
				
			||||||
 | 
					template <typename T, bool INTEGRAL = std::is_integral<T>::value>
 | 
				
			||||||
 | 
					struct make_unsigned_or_unchanged {
 | 
				
			||||||
 | 
					  using type = T;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename T> struct make_unsigned_or_unchanged<T, true> {
 | 
				
			||||||
 | 
					  using type = typename std::make_unsigned<T>::type;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if FMT_SAFE_DURATION_CAST
 | 
				
			||||||
 | 
					// throwing version of safe_duration_cast
 | 
				
			||||||
 | 
					template <typename To, typename FromRep, typename FromPeriod>
 | 
				
			||||||
 | 
					To fmt_safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from) {
 | 
				
			||||||
 | 
					  int ec;
 | 
				
			||||||
 | 
					  To to = safe_duration_cast::safe_duration_cast<To>(from, ec);
 | 
				
			||||||
 | 
					  if (ec) FMT_THROW(format_error("cannot format duration"));
 | 
				
			||||||
 | 
					  return to;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Rep, typename Period,
 | 
				
			||||||
 | 
					          FMT_ENABLE_IF(std::is_integral<Rep>::value)>
 | 
				
			||||||
 | 
					inline std::chrono::duration<Rep, std::milli> get_milliseconds(
 | 
				
			||||||
 | 
					    std::chrono::duration<Rep, Period> d) {
 | 
				
			||||||
 | 
					  // this may overflow and/or the result may not fit in the
 | 
				
			||||||
 | 
					  // target type.
 | 
				
			||||||
 | 
					#if FMT_SAFE_DURATION_CAST
 | 
				
			||||||
 | 
					  using CommonSecondsType =
 | 
				
			||||||
 | 
					      typename std::common_type<decltype(d), std::chrono::seconds>::type;
 | 
				
			||||||
 | 
					  const auto d_as_common = fmt_safe_duration_cast<CommonSecondsType>(d);
 | 
				
			||||||
 | 
					  const auto d_as_whole_seconds =
 | 
				
			||||||
 | 
					      fmt_safe_duration_cast<std::chrono::seconds>(d_as_common);
 | 
				
			||||||
 | 
					  // this conversion should be nonproblematic
 | 
				
			||||||
 | 
					  const auto diff = d_as_common - d_as_whole_seconds;
 | 
				
			||||||
 | 
					  const auto ms =
 | 
				
			||||||
 | 
					      fmt_safe_duration_cast<std::chrono::duration<Rep, std::milli>>(diff);
 | 
				
			||||||
 | 
					  return ms;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					  auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
 | 
				
			||||||
 | 
					  return std::chrono::duration_cast<std::chrono::milliseconds>(d - s);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Rep, typename Period,
 | 
				
			||||||
 | 
					          FMT_ENABLE_IF(std::is_floating_point<Rep>::value)>
 | 
				
			||||||
 | 
					inline std::chrono::duration<Rep, std::milli> get_milliseconds(
 | 
				
			||||||
 | 
					    std::chrono::duration<Rep, Period> d) {
 | 
				
			||||||
 | 
					  using common_type = typename std::common_type<Rep, std::intmax_t>::type;
 | 
				
			||||||
 | 
					  auto ms = mod(d.count() * static_cast<common_type>(Period::num) /
 | 
				
			||||||
 | 
					                    static_cast<common_type>(Period::den) * 1000,
 | 
				
			||||||
 | 
					                1000);
 | 
				
			||||||
 | 
					  return std::chrono::duration<Rep, std::milli>(static_cast<Rep>(ms));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Rep, typename OutputIt>
 | 
				
			||||||
 | 
					OutputIt format_chrono_duration_value(OutputIt out, Rep val, int precision) {
 | 
				
			||||||
 | 
					  if (precision >= 0) return format_to(out, "{:.{}f}", val, precision);
 | 
				
			||||||
 | 
					  return format_to(out, std::is_floating_point<Rep>::value ? "{:g}" : "{}",
 | 
				
			||||||
 | 
					                   val);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Period, typename OutputIt>
 | 
				
			||||||
 | 
					static OutputIt format_chrono_duration_unit(OutputIt out) {
 | 
				
			||||||
 | 
					  if (const char* unit = get_units<Period>()) return format_to(out, "{}", unit);
 | 
				
			||||||
 | 
					  if (Period::den == 1) return format_to(out, "[{}]s", Period::num);
 | 
				
			||||||
 | 
					  return format_to(out, "[{}/{}]s", Period::num, Period::den);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename FormatContext, typename OutputIt, typename Rep,
 | 
				
			||||||
 | 
					          typename Period>
 | 
				
			||||||
struct chrono_formatter {
 | 
					struct chrono_formatter {
 | 
				
			||||||
  FormatContext &context;
 | 
					  FormatContext& context;
 | 
				
			||||||
  OutputIt out;
 | 
					  OutputIt out;
 | 
				
			||||||
  std::chrono::seconds s;
 | 
					  int precision;
 | 
				
			||||||
  std::chrono::milliseconds ms;
 | 
					  // rep is unsigned to avoid overflow.
 | 
				
			||||||
 | 
					  using rep =
 | 
				
			||||||
 | 
					      conditional_t<std::is_integral<Rep>::value && sizeof(Rep) < sizeof(int),
 | 
				
			||||||
 | 
					                    unsigned, typename make_unsigned_or_unchanged<Rep>::type>;
 | 
				
			||||||
 | 
					  rep val;
 | 
				
			||||||
 | 
					  using seconds = std::chrono::duration<rep>;
 | 
				
			||||||
 | 
					  seconds s;
 | 
				
			||||||
 | 
					  using milliseconds = std::chrono::duration<rep, std::milli>;
 | 
				
			||||||
 | 
					  bool negative;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  typedef typename FormatContext::char_type char_type;
 | 
					  using char_type = typename FormatContext::char_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  explicit chrono_formatter(FormatContext &ctx, OutputIt o)
 | 
					  explicit chrono_formatter(FormatContext& ctx, OutputIt o,
 | 
				
			||||||
    : context(ctx), out(o) {}
 | 
					                            std::chrono::duration<Rep, Period> d)
 | 
				
			||||||
 | 
					      : context(ctx), out(o), val(d.count()), negative(false) {
 | 
				
			||||||
  int hour() const { return to_int((s.count() / 3600) % 24); }
 | 
					    if (d.count() < 0) {
 | 
				
			||||||
 | 
					      val = 0 - val;
 | 
				
			||||||
  int hour12() const {
 | 
					      negative = true;
 | 
				
			||||||
    auto hour = to_int((s.count() / 3600) % 12);
 | 
					 | 
				
			||||||
    return hour > 0 ? hour : 12;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int minute() const { return to_int((s.count() / 60) % 60); }
 | 
					    // this may overflow and/or the result may not fit in the
 | 
				
			||||||
  int second() const { return to_int(s.count() % 60); }
 | 
					    // target type.
 | 
				
			||||||
 | 
					#if FMT_SAFE_DURATION_CAST
 | 
				
			||||||
 | 
					    // might need checked conversion (rep!=Rep)
 | 
				
			||||||
 | 
					    auto tmpval = std::chrono::duration<rep, Period>(val);
 | 
				
			||||||
 | 
					    s = fmt_safe_duration_cast<seconds>(tmpval);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    s = std::chrono::duration_cast<seconds>(
 | 
				
			||||||
 | 
					        std::chrono::duration<rep, Period>(val));
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // returns true if nan or inf, writes to out.
 | 
				
			||||||
 | 
					  bool handle_nan_inf() {
 | 
				
			||||||
 | 
					    if (isfinite(val)) {
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (isnan(val)) {
 | 
				
			||||||
 | 
					      write_nan();
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // must be +-inf
 | 
				
			||||||
 | 
					    if (val > 0) {
 | 
				
			||||||
 | 
					      write_pinf();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      write_ninf();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Rep hour() const { return static_cast<Rep>(mod((s.count() / 3600), 24)); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Rep hour12() const {
 | 
				
			||||||
 | 
					    Rep hour = static_cast<Rep>(mod((s.count() / 3600), 12));
 | 
				
			||||||
 | 
					    return hour <= 0 ? 12 : hour;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Rep minute() const { return static_cast<Rep>(mod((s.count() / 60), 60)); }
 | 
				
			||||||
 | 
					  Rep second() const { return static_cast<Rep>(mod(s.count(), 60)); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::tm time() const {
 | 
					  std::tm time() const {
 | 
				
			||||||
    auto time = std::tm();
 | 
					    auto time = std::tm();
 | 
				
			||||||
    time.tm_hour = hour();
 | 
					    time.tm_hour = to_nonnegative_int(hour(), 24);
 | 
				
			||||||
    time.tm_min = minute();
 | 
					    time.tm_min = to_nonnegative_int(minute(), 60);
 | 
				
			||||||
    time.tm_sec = second();
 | 
					    time.tm_sec = to_nonnegative_int(second(), 60);
 | 
				
			||||||
    return time;
 | 
					    return time;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void write(int value, int width) {
 | 
					  void write_sign() {
 | 
				
			||||||
    typedef typename int_traits<int>::main_type main_type;
 | 
					    if (negative) {
 | 
				
			||||||
    main_type n = to_unsigned(value);
 | 
					      *out++ = '-';
 | 
				
			||||||
 | 
					      negative = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void write(Rep value, int width) {
 | 
				
			||||||
 | 
					    write_sign();
 | 
				
			||||||
 | 
					    if (isnan(value)) return write_nan();
 | 
				
			||||||
 | 
					    uint32_or_64_t<int> n = to_unsigned(
 | 
				
			||||||
 | 
					        to_nonnegative_int(value, (std::numeric_limits<int>::max)()));
 | 
				
			||||||
    int num_digits = internal::count_digits(n);
 | 
					    int num_digits = internal::count_digits(n);
 | 
				
			||||||
    if (width > num_digits)
 | 
					    if (width > num_digits) out = std::fill_n(out, width - num_digits, '0');
 | 
				
			||||||
      out = std::fill_n(out, width - num_digits, '0');
 | 
					 | 
				
			||||||
    out = format_decimal<char_type>(out, n, num_digits);
 | 
					    out = format_decimal<char_type>(out, n, num_digits);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void format_localized(const tm &time, const char *format) {
 | 
					  void write_nan() { std::copy_n("nan", 3, out); }
 | 
				
			||||||
 | 
					  void write_pinf() { std::copy_n("inf", 3, out); }
 | 
				
			||||||
 | 
					  void write_ninf() { std::copy_n("-inf", 4, out); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void format_localized(const tm& time, const char* format) {
 | 
				
			||||||
 | 
					    if (isnan(val)) return write_nan();
 | 
				
			||||||
    auto locale = context.locale().template get<std::locale>();
 | 
					    auto locale = context.locale().template get<std::locale>();
 | 
				
			||||||
    auto &facet = std::use_facet<std::time_put<char_type>>(locale);
 | 
					    auto& facet = std::use_facet<std::time_put<char_type>>(locale);
 | 
				
			||||||
    std::basic_ostringstream<char_type> os;
 | 
					    std::basic_ostringstream<char_type> os;
 | 
				
			||||||
    os.imbue(locale);
 | 
					    os.imbue(locale);
 | 
				
			||||||
    facet.put(os, os, ' ', &time, format, format + std::strlen(format));
 | 
					    facet.put(os, os, ' ', &time, format, format + std::strlen(format));
 | 
				
			||||||
@ -266,7 +604,7 @@ struct chrono_formatter {
 | 
				
			|||||||
    std::copy(str.begin(), str.end(), out);
 | 
					    std::copy(str.begin(), str.end(), out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void on_text(const char_type *begin, const char_type *end) {
 | 
					  void on_text(const char_type* begin, const char_type* end) {
 | 
				
			||||||
    std::copy(begin, end, out);
 | 
					    std::copy(begin, end, out);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -286,46 +624,70 @@ struct chrono_formatter {
 | 
				
			|||||||
  void on_tz_name() {}
 | 
					  void on_tz_name() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void on_24_hour(numeric_system ns) {
 | 
					  void on_24_hour(numeric_system ns) {
 | 
				
			||||||
    if (ns == numeric_system::standard)
 | 
					    if (handle_nan_inf()) return;
 | 
				
			||||||
      return write(hour(), 2);
 | 
					
 | 
				
			||||||
 | 
					    if (ns == numeric_system::standard) return write(hour(), 2);
 | 
				
			||||||
    auto time = tm();
 | 
					    auto time = tm();
 | 
				
			||||||
    time.tm_hour = hour();
 | 
					    time.tm_hour = to_nonnegative_int(hour(), 24);
 | 
				
			||||||
    format_localized(time, "%OH");
 | 
					    format_localized(time, "%OH");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void on_12_hour(numeric_system ns) {
 | 
					  void on_12_hour(numeric_system ns) {
 | 
				
			||||||
    if (ns == numeric_system::standard)
 | 
					    if (handle_nan_inf()) return;
 | 
				
			||||||
      return write(hour12(), 2);
 | 
					
 | 
				
			||||||
 | 
					    if (ns == numeric_system::standard) return write(hour12(), 2);
 | 
				
			||||||
    auto time = tm();
 | 
					    auto time = tm();
 | 
				
			||||||
    time.tm_hour = hour();
 | 
					    time.tm_hour = to_nonnegative_int(hour12(), 12);
 | 
				
			||||||
    format_localized(time, "%OI");
 | 
					    format_localized(time, "%OI");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void on_minute(numeric_system ns) {
 | 
					  void on_minute(numeric_system ns) {
 | 
				
			||||||
    if (ns == numeric_system::standard)
 | 
					    if (handle_nan_inf()) return;
 | 
				
			||||||
      return write(minute(), 2);
 | 
					
 | 
				
			||||||
 | 
					    if (ns == numeric_system::standard) return write(minute(), 2);
 | 
				
			||||||
    auto time = tm();
 | 
					    auto time = tm();
 | 
				
			||||||
    time.tm_min = minute();
 | 
					    time.tm_min = to_nonnegative_int(minute(), 60);
 | 
				
			||||||
    format_localized(time, "%OM");
 | 
					    format_localized(time, "%OM");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void on_second(numeric_system ns) {
 | 
					  void on_second(numeric_system ns) {
 | 
				
			||||||
 | 
					    if (handle_nan_inf()) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (ns == numeric_system::standard) {
 | 
					    if (ns == numeric_system::standard) {
 | 
				
			||||||
      write(second(), 2);
 | 
					      write(second(), 2);
 | 
				
			||||||
 | 
					#if FMT_SAFE_DURATION_CAST
 | 
				
			||||||
 | 
					      // convert rep->Rep
 | 
				
			||||||
 | 
					      using duration_rep = std::chrono::duration<rep, Period>;
 | 
				
			||||||
 | 
					      using duration_Rep = std::chrono::duration<Rep, Period>;
 | 
				
			||||||
 | 
					      auto tmpval = fmt_safe_duration_cast<duration_Rep>(duration_rep{val});
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					      auto tmpval = std::chrono::duration<Rep, Period>(val);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					      auto ms = get_milliseconds(tmpval);
 | 
				
			||||||
      if (ms != std::chrono::milliseconds(0)) {
 | 
					      if (ms != std::chrono::milliseconds(0)) {
 | 
				
			||||||
        *out++ = '.';
 | 
					        *out++ = '.';
 | 
				
			||||||
        write(to_int(ms.count()), 3);
 | 
					        write(ms.count(), 3);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    auto time = tm();
 | 
					    auto time = tm();
 | 
				
			||||||
    time.tm_sec = second();
 | 
					    time.tm_sec = to_nonnegative_int(second(), 60);
 | 
				
			||||||
    format_localized(time, "%OS");
 | 
					    format_localized(time, "%OS");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void on_12_hour_time() { format_localized(time(), "%r"); }
 | 
					  void on_12_hour_time() {
 | 
				
			||||||
 | 
					    if (handle_nan_inf()) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    format_localized(time(), "%r");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void on_24_hour_time() {
 | 
					  void on_24_hour_time() {
 | 
				
			||||||
 | 
					    if (handle_nan_inf()) {
 | 
				
			||||||
 | 
					      *out++ = ':';
 | 
				
			||||||
 | 
					      handle_nan_inf();
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    write(hour(), 2);
 | 
					    write(hour(), 2);
 | 
				
			||||||
    *out++ = ':';
 | 
					    *out++ = ':';
 | 
				
			||||||
    write(minute(), 2);
 | 
					    write(minute(), 2);
 | 
				
			||||||
@ -334,115 +696,130 @@ struct chrono_formatter {
 | 
				
			|||||||
  void on_iso_time() {
 | 
					  void on_iso_time() {
 | 
				
			||||||
    on_24_hour_time();
 | 
					    on_24_hour_time();
 | 
				
			||||||
    *out++ = ':';
 | 
					    *out++ = ':';
 | 
				
			||||||
 | 
					    if (handle_nan_inf()) return;
 | 
				
			||||||
    write(second(), 2);
 | 
					    write(second(), 2);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void on_am_pm() { format_localized(time(), "%p"); }
 | 
					  void on_am_pm() {
 | 
				
			||||||
 | 
					    if (handle_nan_inf()) return;
 | 
				
			||||||
 | 
					    format_localized(time(), "%p");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void on_duration_value() {
 | 
				
			||||||
 | 
					    if (handle_nan_inf()) return;
 | 
				
			||||||
 | 
					    write_sign();
 | 
				
			||||||
 | 
					    out = format_chrono_duration_value(out, val, precision);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void on_duration_unit() { out = format_chrono_duration_unit<Period>(out); }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
}  // namespace internal
 | 
					}  // namespace internal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename Period> FMT_CONSTEXPR const char *get_units() {
 | 
					 | 
				
			||||||
  return FMT_NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::atto>() { return "as"; }
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::femto>() { return "fs"; }
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::pico>() { return "ps"; }
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::nano>() { return "ns"; }
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::micro>() { return "µs"; }
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::milli>() { return "ms"; }
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::centi>() { return "cs"; }
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::deci>() { return "ds"; }
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::ratio<1>>() { return "s"; }
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::deca>() { return "das"; }
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::hecto>() { return "hs"; }
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::kilo>() { return "ks"; }
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::mega>() { return "Ms"; }
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::giga>() { return "Gs"; }
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::tera>() { return "Ts"; }
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::peta>() { return "Ps"; }
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::exa>() { return "Es"; }
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::ratio<60>>() {
 | 
					 | 
				
			||||||
  return "m";
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
template <> FMT_CONSTEXPR const char *get_units<std::ratio<3600>>() {
 | 
					 | 
				
			||||||
  return "h";
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template <typename Rep, typename Period, typename Char>
 | 
					template <typename Rep, typename Period, typename Char>
 | 
				
			||||||
struct formatter<std::chrono::duration<Rep, Period>, Char> {
 | 
					struct formatter<std::chrono::duration<Rep, Period>, Char> {
 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  align_spec spec;
 | 
					  basic_format_specs<Char> specs;
 | 
				
			||||||
  internal::arg_ref<Char> width_ref;
 | 
					  int precision;
 | 
				
			||||||
 | 
					  using arg_ref_type = internal::arg_ref<Char>;
 | 
				
			||||||
 | 
					  arg_ref_type width_ref;
 | 
				
			||||||
 | 
					  arg_ref_type precision_ref;
 | 
				
			||||||
  mutable basic_string_view<Char> format_str;
 | 
					  mutable basic_string_view<Char> format_str;
 | 
				
			||||||
  typedef std::chrono::duration<Rep, Period> duration;
 | 
					  using duration = std::chrono::duration<Rep, Period>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct spec_handler {
 | 
					  struct spec_handler {
 | 
				
			||||||
    formatter &f;
 | 
					    formatter& f;
 | 
				
			||||||
    basic_parse_context<Char> &context;
 | 
					    basic_parse_context<Char>& context;
 | 
				
			||||||
 | 
					    basic_string_view<Char> format_str;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    typedef internal::arg_ref<Char> arg_ref_type;
 | 
					    template <typename Id> FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    template <typename Id>
 | 
					 | 
				
			||||||
    FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {
 | 
					 | 
				
			||||||
      context.check_arg_id(arg_id);
 | 
					      context.check_arg_id(arg_id);
 | 
				
			||||||
      return arg_ref_type(arg_id);
 | 
					      return arg_ref_type(arg_id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view<Char> arg_id) {
 | 
				
			||||||
 | 
					      context.check_arg_id(arg_id);
 | 
				
			||||||
 | 
					      const auto str_val = internal::string_view_metadata(format_str, arg_id);
 | 
				
			||||||
 | 
					      return arg_ref_type(str_val);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    FMT_CONSTEXPR arg_ref_type make_arg_ref(internal::auto_id) {
 | 
					    FMT_CONSTEXPR arg_ref_type make_arg_ref(internal::auto_id) {
 | 
				
			||||||
      return arg_ref_type(context.next_arg_id());
 | 
					      return arg_ref_type(context.next_arg_id());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void on_error(const char *msg) { throw format_error(msg); }
 | 
					    void on_error(const char* msg) { FMT_THROW(format_error(msg)); }
 | 
				
			||||||
    void on_fill(Char fill) { f.spec.fill_ = fill; }
 | 
					    void on_fill(Char fill) { f.specs.fill[0] = fill; }
 | 
				
			||||||
    void on_align(alignment align) { f.spec.align_ = align; }
 | 
					    void on_align(align_t align) { f.specs.align = align; }
 | 
				
			||||||
    void on_width(unsigned width) { f.spec.width_ = width; }
 | 
					    void on_width(unsigned width) { f.specs.width = width; }
 | 
				
			||||||
 | 
					    void on_precision(unsigned precision) { f.precision = precision; }
 | 
				
			||||||
 | 
					    void end_precision() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    template <typename Id>
 | 
					    template <typename Id> void on_dynamic_width(Id arg_id) {
 | 
				
			||||||
    void on_dynamic_width(Id arg_id) {
 | 
					 | 
				
			||||||
      f.width_ref = make_arg_ref(arg_id);
 | 
					      f.width_ref = make_arg_ref(arg_id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename Id> void on_dynamic_precision(Id arg_id) {
 | 
				
			||||||
 | 
					      f.precision_ref = make_arg_ref(arg_id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 public:
 | 
					  using iterator = typename basic_parse_context<Char>::iterator;
 | 
				
			||||||
  formatter() : spec() {}
 | 
					  struct parse_range {
 | 
				
			||||||
 | 
					    iterator begin;
 | 
				
			||||||
 | 
					    iterator end;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  FMT_CONSTEXPR auto parse(basic_parse_context<Char> &ctx)
 | 
					  FMT_CONSTEXPR parse_range do_parse(basic_parse_context<Char>& ctx) {
 | 
				
			||||||
      -> decltype(ctx.begin()) {
 | 
					 | 
				
			||||||
    auto begin = ctx.begin(), end = ctx.end();
 | 
					    auto begin = ctx.begin(), end = ctx.end();
 | 
				
			||||||
    if (begin == end) return begin;
 | 
					    if (begin == end || *begin == '}') return {begin, begin};
 | 
				
			||||||
    spec_handler handler{*this, ctx};
 | 
					    spec_handler handler{*this, ctx, format_str};
 | 
				
			||||||
    begin = internal::parse_align(begin, end, handler);
 | 
					    begin = internal::parse_align(begin, end, handler);
 | 
				
			||||||
    if (begin == end) return begin;
 | 
					    if (begin == end) return {begin, begin};
 | 
				
			||||||
    begin = internal::parse_width(begin, end, handler);
 | 
					    begin = internal::parse_width(begin, end, handler);
 | 
				
			||||||
 | 
					    if (begin == end) return {begin, begin};
 | 
				
			||||||
 | 
					    if (*begin == '.') {
 | 
				
			||||||
 | 
					      if (std::is_floating_point<Rep>::value)
 | 
				
			||||||
 | 
					        begin = internal::parse_precision(begin, end, handler);
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        handler.on_error("precision not allowed for this argument type");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    end = parse_chrono_format(begin, end, internal::chrono_format_checker());
 | 
					    end = parse_chrono_format(begin, end, internal::chrono_format_checker());
 | 
				
			||||||
    format_str = basic_string_view<Char>(&*begin, internal::to_unsigned(end - begin));
 | 
					    return {begin, end};
 | 
				
			||||||
    return end;
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  formatter() : precision(-1) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR auto parse(basic_parse_context<Char>& ctx)
 | 
				
			||||||
 | 
					      -> decltype(ctx.begin()) {
 | 
				
			||||||
 | 
					    auto range = do_parse(ctx);
 | 
				
			||||||
 | 
					    format_str = basic_string_view<Char>(
 | 
				
			||||||
 | 
					        &*range.begin, internal::to_unsigned(range.end - range.begin));
 | 
				
			||||||
 | 
					    return range.end;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template <typename FormatContext>
 | 
					  template <typename FormatContext>
 | 
				
			||||||
  auto format(const duration &d, FormatContext &ctx)
 | 
					  auto format(const duration& d, FormatContext& ctx) -> decltype(ctx.out()) {
 | 
				
			||||||
      -> decltype(ctx.out()) {
 | 
					 | 
				
			||||||
    auto begin = format_str.begin(), end = format_str.end();
 | 
					    auto begin = format_str.begin(), end = format_str.end();
 | 
				
			||||||
    memory_buffer buf;
 | 
					    // As a possible future optimization, we could avoid extra copying if width
 | 
				
			||||||
    typedef output_range<decltype(ctx.out()), Char> range;
 | 
					    // is not specified.
 | 
				
			||||||
    basic_writer<range> w(range(ctx.out()));
 | 
					    basic_memory_buffer<Char> buf;
 | 
				
			||||||
    if (begin == end || *begin == '}') {
 | 
					 | 
				
			||||||
      if (const char *unit = get_units<Period>())
 | 
					 | 
				
			||||||
        format_to(buf, "{}{}", d.count(), unit);
 | 
					 | 
				
			||||||
      else if (Period::den == 1)
 | 
					 | 
				
			||||||
        format_to(buf, "{}[{}]s", d.count(), Period::num);
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        format_to(buf, "{}[{}/{}]s", d.count(), Period::num, Period::den);
 | 
					 | 
				
			||||||
      internal::handle_dynamic_spec<internal::width_checker>(
 | 
					 | 
				
			||||||
        spec.width_, width_ref, ctx);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
    auto out = std::back_inserter(buf);
 | 
					    auto out = std::back_inserter(buf);
 | 
				
			||||||
      internal::chrono_formatter<FormatContext, decltype(out)> f(ctx, out);
 | 
					    using range = internal::output_range<decltype(ctx.out()), Char>;
 | 
				
			||||||
      f.s = std::chrono::duration_cast<std::chrono::seconds>(d);
 | 
					    internal::basic_writer<range> w(range(ctx.out()));
 | 
				
			||||||
      f.ms = std::chrono::duration_cast<std::chrono::milliseconds>(d - f.s);
 | 
					    internal::handle_dynamic_spec<internal::width_checker>(
 | 
				
			||||||
 | 
					        specs.width, width_ref, ctx, format_str.begin());
 | 
				
			||||||
 | 
					    internal::handle_dynamic_spec<internal::precision_checker>(
 | 
				
			||||||
 | 
					        precision, precision_ref, ctx, format_str.begin());
 | 
				
			||||||
 | 
					    if (begin == end || *begin == '}') {
 | 
				
			||||||
 | 
					      out = internal::format_chrono_duration_value(out, d.count(), precision);
 | 
				
			||||||
 | 
					      internal::format_chrono_duration_unit<Period>(out);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      internal::chrono_formatter<FormatContext, decltype(out), Rep, Period> f(
 | 
				
			||||||
 | 
					          ctx, out, d);
 | 
				
			||||||
 | 
					      f.precision = precision;
 | 
				
			||||||
      parse_chrono_format(begin, end, f);
 | 
					      parse_chrono_format(begin, end, f);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    w.write(buf.data(), buf.size(), spec);
 | 
					    w.write(buf.data(), buf.size(), specs);
 | 
				
			||||||
    return w.out();
 | 
					    return w.out();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -12,41 +12,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
FMT_BEGIN_NAMESPACE
 | 
					FMT_BEGIN_NAMESPACE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef FMT_DEPRECATED_COLORS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// color and (v)print_colored are deprecated.
 | 
					 | 
				
			||||||
enum color { black, red, green, yellow, blue, magenta, cyan, white };
 | 
					 | 
				
			||||||
FMT_API void vprint_colored(color c, string_view format, format_args args);
 | 
					 | 
				
			||||||
FMT_API void vprint_colored(color c, wstring_view format, wformat_args args);
 | 
					 | 
				
			||||||
template <typename... Args>
 | 
					 | 
				
			||||||
inline void print_colored(color c, string_view format_str,
 | 
					 | 
				
			||||||
                          const Args & ... args) {
 | 
					 | 
				
			||||||
  vprint_colored(c, format_str, make_format_args(args...));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
template <typename... Args>
 | 
					 | 
				
			||||||
inline void print_colored(color c, wstring_view format_str,
 | 
					 | 
				
			||||||
                          const Args & ... args) {
 | 
					 | 
				
			||||||
  vprint_colored(c, format_str, make_format_args<wformat_context>(args...));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
inline void vprint_colored(color c, string_view format, format_args args) {
 | 
					 | 
				
			||||||
  char escape[] = "\x1b[30m";
 | 
					 | 
				
			||||||
  escape[3] = static_cast<char>('0' + c);
 | 
					 | 
				
			||||||
  std::fputs(escape, stdout);
 | 
					 | 
				
			||||||
  vprint(format, args);
 | 
					 | 
				
			||||||
  std::fputs(internal::data::RESET_COLOR, stdout);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
inline void vprint_colored(color c, wstring_view format, wformat_args args) {
 | 
					 | 
				
			||||||
  wchar_t escape[] = L"\x1b[30m";
 | 
					 | 
				
			||||||
  escape[3] = static_cast<wchar_t>('0' + c);
 | 
					 | 
				
			||||||
  std::fputws(escape, stdout);
 | 
					 | 
				
			||||||
  vprint(format, args);
 | 
					 | 
				
			||||||
  std::fputws(internal::data::WRESET_COLOR, stdout);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum class color : uint32_t {
 | 
					enum class color : uint32_t {
 | 
				
			||||||
  alice_blue = 0xF0F8FF,               // rgb(240,248,255)
 | 
					  alice_blue = 0xF0F8FF,               // rgb(240,248,255)
 | 
				
			||||||
  antique_white = 0xFAEBD7,            // rgb(250,235,215)
 | 
					  antique_white = 0xFAEBD7,            // rgb(250,235,215)
 | 
				
			||||||
@ -208,26 +173,25 @@ enum class terminal_color : uint8_t {
 | 
				
			|||||||
  bright_magenta,
 | 
					  bright_magenta,
 | 
				
			||||||
  bright_cyan,
 | 
					  bright_cyan,
 | 
				
			||||||
  bright_white
 | 
					  bright_white
 | 
				
			||||||
};  // enum class terminal_color
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class emphasis : uint8_t {
 | 
					enum class emphasis : uint8_t {
 | 
				
			||||||
  bold = 1,
 | 
					  bold = 1,
 | 
				
			||||||
  italic = 1 << 1,
 | 
					  italic = 1 << 1,
 | 
				
			||||||
  underline = 1 << 2,
 | 
					  underline = 1 << 2,
 | 
				
			||||||
  strikethrough = 1 << 3
 | 
					  strikethrough = 1 << 3
 | 
				
			||||||
};  // enum class emphasis
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// rgb is a struct for red, green and blue colors.
 | 
					// rgb is a struct for red, green and blue colors.
 | 
				
			||||||
// We use rgb as name because some editors will show it as color direct in the
 | 
					// Using the name "rgb" makes some editors show the color in a tooltip.
 | 
				
			||||||
// editor.
 | 
					 | 
				
			||||||
struct rgb {
 | 
					struct rgb {
 | 
				
			||||||
  FMT_CONSTEXPR_DECL rgb() : r(0), g(0), b(0) {}
 | 
					  FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {}
 | 
				
			||||||
  FMT_CONSTEXPR_DECL rgb(uint8_t r_, uint8_t g_, uint8_t b_)
 | 
					  FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {}
 | 
				
			||||||
    : r(r_), g(g_), b(b_) {}
 | 
					  FMT_CONSTEXPR rgb(uint32_t hex)
 | 
				
			||||||
  FMT_CONSTEXPR_DECL rgb(uint32_t hex)
 | 
					      : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {}
 | 
				
			||||||
    : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b((hex) & 0xFF) {}
 | 
					  FMT_CONSTEXPR rgb(color hex)
 | 
				
			||||||
  FMT_CONSTEXPR_DECL rgb(color hex)
 | 
					      : r((uint32_t(hex) >> 16) & 0xFF),
 | 
				
			||||||
    : r((uint32_t(hex) >> 16) & 0xFF), g((uint32_t(hex) >> 8) & 0xFF),
 | 
					        g((uint32_t(hex) >> 8) & 0xFF),
 | 
				
			||||||
        b(uint32_t(hex) & 0xFF) {}
 | 
					        b(uint32_t(hex) & 0xFF) {}
 | 
				
			||||||
  uint8_t r;
 | 
					  uint8_t r;
 | 
				
			||||||
  uint8_t g;
 | 
					  uint8_t g;
 | 
				
			||||||
@ -238,19 +202,17 @@ namespace internal {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// color is a struct of either a rgb color or a terminal color.
 | 
					// color is a struct of either a rgb color or a terminal color.
 | 
				
			||||||
struct color_type {
 | 
					struct color_type {
 | 
				
			||||||
  FMT_CONSTEXPR color_type() FMT_NOEXCEPT
 | 
					  FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {}
 | 
				
			||||||
    : is_rgb(), value{} {}
 | 
					  FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true),
 | 
				
			||||||
  FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT
 | 
					                                                           value{} {
 | 
				
			||||||
    : is_rgb(true), value{} {
 | 
					 | 
				
			||||||
    value.rgb_color = static_cast<uint32_t>(rgb_color);
 | 
					    value.rgb_color = static_cast<uint32_t>(rgb_color);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT
 | 
					  FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} {
 | 
				
			||||||
    : is_rgb(true), value{} {
 | 
					    value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
 | 
				
			||||||
    value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16)
 | 
					                      (static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
 | 
				
			||||||
       | (static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT
 | 
					  FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(),
 | 
				
			||||||
    : is_rgb(), value{} {
 | 
					                                                                     value{} {
 | 
				
			||||||
    value.term_color = static_cast<uint8_t>(term_color);
 | 
					    value.term_color = static_cast<uint8_t>(term_color);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  bool is_rgb;
 | 
					  bool is_rgb;
 | 
				
			||||||
@ -265,15 +227,17 @@ struct color_type {
 | 
				
			|||||||
class text_style {
 | 
					class text_style {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
 | 
					  FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
 | 
				
			||||||
      : set_foreground_color(), set_background_color(), ems(em) {}
 | 
					      : set_foreground_color(),
 | 
				
			||||||
 | 
					        set_background_color(),
 | 
				
			||||||
 | 
					        ems(em) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  FMT_CONSTEXPR text_style &operator|=(const text_style &rhs) {
 | 
					  FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) {
 | 
				
			||||||
    if (!set_foreground_color) {
 | 
					    if (!set_foreground_color) {
 | 
				
			||||||
      set_foreground_color = rhs.set_foreground_color;
 | 
					      set_foreground_color = rhs.set_foreground_color;
 | 
				
			||||||
      foreground_color = rhs.foreground_color;
 | 
					      foreground_color = rhs.foreground_color;
 | 
				
			||||||
    } else if (rhs.set_foreground_color) {
 | 
					    } else if (rhs.set_foreground_color) {
 | 
				
			||||||
      if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
 | 
					      if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
 | 
				
			||||||
        throw format_error("can't OR a terminal color");
 | 
					        FMT_THROW(format_error("can't OR a terminal color"));
 | 
				
			||||||
      foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color;
 | 
					      foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -282,7 +246,7 @@ class text_style {
 | 
				
			|||||||
      background_color = rhs.background_color;
 | 
					      background_color = rhs.background_color;
 | 
				
			||||||
    } else if (rhs.set_background_color) {
 | 
					    } else if (rhs.set_background_color) {
 | 
				
			||||||
      if (!background_color.is_rgb || !rhs.background_color.is_rgb)
 | 
					      if (!background_color.is_rgb || !rhs.background_color.is_rgb)
 | 
				
			||||||
        throw format_error("can't OR a terminal color");
 | 
					        FMT_THROW(format_error("can't OR a terminal color"));
 | 
				
			||||||
      background_color.value.rgb_color |= rhs.background_color.value.rgb_color;
 | 
					      background_color.value.rgb_color |= rhs.background_color.value.rgb_color;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -291,18 +255,18 @@ class text_style {
 | 
				
			|||||||
    return *this;
 | 
					    return *this;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  friend FMT_CONSTEXPR
 | 
					  friend FMT_CONSTEXPR text_style operator|(text_style lhs,
 | 
				
			||||||
  text_style operator|(text_style lhs, const text_style &rhs) {
 | 
					                                            const text_style& rhs) {
 | 
				
			||||||
    return lhs |= rhs;
 | 
					    return lhs |= rhs;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  FMT_CONSTEXPR text_style &operator&=(const text_style &rhs) {
 | 
					  FMT_CONSTEXPR text_style& operator&=(const text_style& rhs) {
 | 
				
			||||||
    if (!set_foreground_color) {
 | 
					    if (!set_foreground_color) {
 | 
				
			||||||
      set_foreground_color = rhs.set_foreground_color;
 | 
					      set_foreground_color = rhs.set_foreground_color;
 | 
				
			||||||
      foreground_color = rhs.foreground_color;
 | 
					      foreground_color = rhs.foreground_color;
 | 
				
			||||||
    } else if (rhs.set_foreground_color) {
 | 
					    } else if (rhs.set_foreground_color) {
 | 
				
			||||||
      if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
 | 
					      if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
 | 
				
			||||||
        throw format_error("can't AND a terminal color");
 | 
					        FMT_THROW(format_error("can't AND a terminal color"));
 | 
				
			||||||
      foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
 | 
					      foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -311,7 +275,7 @@ class text_style {
 | 
				
			|||||||
      background_color = rhs.background_color;
 | 
					      background_color = rhs.background_color;
 | 
				
			||||||
    } else if (rhs.set_background_color) {
 | 
					    } else if (rhs.set_background_color) {
 | 
				
			||||||
      if (!background_color.is_rgb || !rhs.background_color.is_rgb)
 | 
					      if (!background_color.is_rgb || !rhs.background_color.is_rgb)
 | 
				
			||||||
        throw format_error("can't AND a terminal color");
 | 
					        FMT_THROW(format_error("can't AND a terminal color"));
 | 
				
			||||||
      background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
 | 
					      background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -320,8 +284,8 @@ class text_style {
 | 
				
			|||||||
    return *this;
 | 
					    return *this;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  friend FMT_CONSTEXPR
 | 
					  friend FMT_CONSTEXPR text_style operator&(text_style lhs,
 | 
				
			||||||
  text_style operator&(text_style lhs, const text_style &rhs) {
 | 
					                                            const text_style& rhs) {
 | 
				
			||||||
    return lhs &= rhs;
 | 
					    return lhs &= rhs;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -347,7 +311,7 @@ class text_style {
 | 
				
			|||||||
    return ems;
 | 
					    return ems;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					 private:
 | 
				
			||||||
  FMT_CONSTEXPR text_style(bool is_foreground,
 | 
					  FMT_CONSTEXPR text_style(bool is_foreground,
 | 
				
			||||||
                           internal::color_type text_color) FMT_NOEXCEPT
 | 
					                           internal::color_type text_color) FMT_NOEXCEPT
 | 
				
			||||||
      : set_foreground_color(),
 | 
					      : set_foreground_color(),
 | 
				
			||||||
@ -388,19 +352,17 @@ FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace internal {
 | 
					namespace internal {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename Char>
 | 
					template <typename Char> struct ansi_color_escape {
 | 
				
			||||||
struct ansi_color_escape {
 | 
					 | 
				
			||||||
  FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color,
 | 
					  FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color,
 | 
				
			||||||
                                  const char * esc) FMT_NOEXCEPT {
 | 
					                                  const char* esc) FMT_NOEXCEPT {
 | 
				
			||||||
    // If we have a terminal color, we need to output another escape code
 | 
					    // If we have a terminal color, we need to output another escape code
 | 
				
			||||||
    // sequence.
 | 
					    // sequence.
 | 
				
			||||||
    if (!text_color.is_rgb) {
 | 
					    if (!text_color.is_rgb) {
 | 
				
			||||||
      bool is_background = esc == internal::data::BACKGROUND_COLOR;
 | 
					      bool is_background = esc == internal::data::background_color;
 | 
				
			||||||
      uint32_t value = text_color.value.term_color;
 | 
					      uint32_t value = text_color.value.term_color;
 | 
				
			||||||
      // Background ASCII codes are the same as the foreground ones but with
 | 
					      // Background ASCII codes are the same as the foreground ones but with
 | 
				
			||||||
      // 10 more.
 | 
					      // 10 more.
 | 
				
			||||||
      if (is_background)
 | 
					      if (is_background) value += 10u;
 | 
				
			||||||
        value += 10u;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      std::size_t index = 0;
 | 
					      std::size_t index = 0;
 | 
				
			||||||
      buffer[index++] = static_cast<Char>('\x1b');
 | 
					      buffer[index++] = static_cast<Char>('\x1b');
 | 
				
			||||||
@ -430,19 +392,15 @@ struct ansi_color_escape {
 | 
				
			|||||||
  FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
 | 
					  FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
 | 
				
			||||||
    uint8_t em_codes[4] = {};
 | 
					    uint8_t em_codes[4] = {};
 | 
				
			||||||
    uint8_t em_bits = static_cast<uint8_t>(em);
 | 
					    uint8_t em_bits = static_cast<uint8_t>(em);
 | 
				
			||||||
    if (em_bits & static_cast<uint8_t>(emphasis::bold))
 | 
					    if (em_bits & static_cast<uint8_t>(emphasis::bold)) em_codes[0] = 1;
 | 
				
			||||||
      em_codes[0] = 1;
 | 
					    if (em_bits & static_cast<uint8_t>(emphasis::italic)) em_codes[1] = 3;
 | 
				
			||||||
    if (em_bits & static_cast<uint8_t>(emphasis::italic))
 | 
					    if (em_bits & static_cast<uint8_t>(emphasis::underline)) em_codes[2] = 4;
 | 
				
			||||||
      em_codes[1] = 3;
 | 
					 | 
				
			||||||
    if (em_bits & static_cast<uint8_t>(emphasis::underline))
 | 
					 | 
				
			||||||
      em_codes[2] = 4;
 | 
					 | 
				
			||||||
    if (em_bits & static_cast<uint8_t>(emphasis::strikethrough))
 | 
					    if (em_bits & static_cast<uint8_t>(emphasis::strikethrough))
 | 
				
			||||||
      em_codes[3] = 9;
 | 
					      em_codes[3] = 9;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::size_t index = 0;
 | 
					    std::size_t index = 0;
 | 
				
			||||||
    for (int i = 0; i < 4; ++i) {
 | 
					    for (int i = 0; i < 4; ++i) {
 | 
				
			||||||
      if (!em_codes[i])
 | 
					      if (!em_codes[i]) continue;
 | 
				
			||||||
        continue;
 | 
					 | 
				
			||||||
      buffer[index++] = static_cast<Char>('\x1b');
 | 
					      buffer[index++] = static_cast<Char>('\x1b');
 | 
				
			||||||
      buffer[index++] = static_cast<Char>('[');
 | 
					      buffer[index++] = static_cast<Char>('[');
 | 
				
			||||||
      buffer[index++] = static_cast<Char>('0' + em_codes[i]);
 | 
					      buffer[index++] = static_cast<Char>('0' + em_codes[i]);
 | 
				
			||||||
@ -450,12 +408,17 @@ struct ansi_color_escape {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    buffer[index++] = static_cast<Char>(0);
 | 
					    buffer[index++] = static_cast<Char>(0);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  FMT_CONSTEXPR operator const Char *() const FMT_NOEXCEPT { return buffer; }
 | 
					  FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					  FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; }
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR const Char* end() const FMT_NOEXCEPT {
 | 
				
			||||||
 | 
					    return buffer + std::strlen(buffer);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
  Char buffer[7u + 3u * 4u + 1u];
 | 
					  Char buffer[7u + 3u * 4u + 1u];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static FMT_CONSTEXPR void to_esc(uint8_t c, Char *out,
 | 
					  static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
 | 
				
			||||||
                                   char delimiter) FMT_NOEXCEPT {
 | 
					                                   char delimiter) FMT_NOEXCEPT {
 | 
				
			||||||
    out[0] = static_cast<Char>('0' + c / 100);
 | 
					    out[0] = static_cast<Char>('0' + c / 100);
 | 
				
			||||||
    out[1] = static_cast<Char>('0' + c / 10 % 10);
 | 
					    out[1] = static_cast<Char>('0' + c / 10 % 10);
 | 
				
			||||||
@ -465,62 +428,85 @@ private:
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename Char>
 | 
					template <typename Char>
 | 
				
			||||||
FMT_CONSTEXPR ansi_color_escape<Char>
 | 
					FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
 | 
				
			||||||
make_foreground_color(internal::color_type foreground) FMT_NOEXCEPT {
 | 
					    internal::color_type foreground) FMT_NOEXCEPT {
 | 
				
			||||||
  return ansi_color_escape<Char>(foreground, internal::data::FOREGROUND_COLOR);
 | 
					  return ansi_color_escape<Char>(foreground, internal::data::foreground_color);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename Char>
 | 
					template <typename Char>
 | 
				
			||||||
FMT_CONSTEXPR ansi_color_escape<Char>
 | 
					FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
 | 
				
			||||||
make_background_color(internal::color_type background) FMT_NOEXCEPT {
 | 
					    internal::color_type background) FMT_NOEXCEPT {
 | 
				
			||||||
  return ansi_color_escape<Char>(background, internal::data::BACKGROUND_COLOR);
 | 
					  return ansi_color_escape<Char>(background, internal::data::background_color);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename Char>
 | 
					template <typename Char>
 | 
				
			||||||
FMT_CONSTEXPR ansi_color_escape<Char>
 | 
					FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) FMT_NOEXCEPT {
 | 
				
			||||||
make_emphasis(emphasis em) FMT_NOEXCEPT {
 | 
					 | 
				
			||||||
  return ansi_color_escape<Char>(em);
 | 
					  return ansi_color_escape<Char>(em);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename Char>
 | 
					template <typename Char>
 | 
				
			||||||
inline void fputs(const Char *chars, FILE *stream) FMT_NOEXCEPT {
 | 
					inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT {
 | 
				
			||||||
  std::fputs(chars, stream);
 | 
					  std::fputs(chars, stream);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <>
 | 
					template <>
 | 
				
			||||||
inline void fputs<wchar_t>(const wchar_t *chars, FILE *stream) FMT_NOEXCEPT {
 | 
					inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT {
 | 
				
			||||||
  std::fputws(chars, stream);
 | 
					  std::fputws(chars, stream);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Char> inline void reset_color(FILE* stream) FMT_NOEXCEPT {
 | 
				
			||||||
 | 
					  fputs(internal::data::reset_color, stream);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT {
 | 
				
			||||||
 | 
					  fputs(internal::data::wreset_color, stream);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename Char>
 | 
					template <typename Char>
 | 
				
			||||||
inline void reset_color(FILE *stream) FMT_NOEXCEPT {
 | 
					inline void reset_color(basic_memory_buffer<Char>& buffer) FMT_NOEXCEPT {
 | 
				
			||||||
  fputs(internal::data::RESET_COLOR, stream);
 | 
					  const char* begin = data::reset_color;
 | 
				
			||||||
 | 
					  const char* end = begin + sizeof(data::reset_color) - 1;
 | 
				
			||||||
 | 
					  buffer.append(begin, end);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <>
 | 
					template <typename Char>
 | 
				
			||||||
inline void reset_color<wchar_t>(FILE *stream) FMT_NOEXCEPT {
 | 
					std::basic_string<Char> vformat(const text_style& ts,
 | 
				
			||||||
  fputs(internal::data::WRESET_COLOR, stream);
 | 
					                                basic_string_view<Char> format_str,
 | 
				
			||||||
}
 | 
					                                basic_format_args<buffer_context<Char> > args) {
 | 
				
			||||||
 | 
					  basic_memory_buffer<Char> buffer;
 | 
				
			||||||
// The following specialiazation disables using std::FILE as a character type,
 | 
					 | 
				
			||||||
// which is needed because or else
 | 
					 | 
				
			||||||
//   fmt::print(stderr, fmt::emphasis::bold, "");
 | 
					 | 
				
			||||||
// would take stderr (a std::FILE *) as the format string.
 | 
					 | 
				
			||||||
template <>
 | 
					 | 
				
			||||||
struct is_string<std::FILE *> : std::false_type {};
 | 
					 | 
				
			||||||
template <>
 | 
					 | 
				
			||||||
struct is_string<const std::FILE *> : std::false_type {};
 | 
					 | 
				
			||||||
} // namespace internal
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template <
 | 
					 | 
				
			||||||
  typename S, typename Char = typename internal::char_t<S>::type>
 | 
					 | 
				
			||||||
void vprint(std::FILE *f, const text_style &ts, const S &format,
 | 
					 | 
				
			||||||
            basic_format_args<typename buffer_context<Char>::type> args) {
 | 
					 | 
				
			||||||
  bool has_style = false;
 | 
					  bool has_style = false;
 | 
				
			||||||
  if (ts.has_emphasis()) {
 | 
					  if (ts.has_emphasis()) {
 | 
				
			||||||
    has_style = true;
 | 
					    has_style = true;
 | 
				
			||||||
    internal::fputs<Char>(
 | 
					    ansi_color_escape<Char> escape = make_emphasis<Char>(ts.get_emphasis());
 | 
				
			||||||
          internal::make_emphasis<Char>(ts.get_emphasis()), f);
 | 
					    buffer.append(escape.begin(), escape.end());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (ts.has_foreground()) {
 | 
				
			||||||
 | 
					    has_style = true;
 | 
				
			||||||
 | 
					    ansi_color_escape<Char> escape =
 | 
				
			||||||
 | 
					        make_foreground_color<Char>(ts.get_foreground());
 | 
				
			||||||
 | 
					    buffer.append(escape.begin(), escape.end());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (ts.has_background()) {
 | 
				
			||||||
 | 
					    has_style = true;
 | 
				
			||||||
 | 
					    ansi_color_escape<Char> escape =
 | 
				
			||||||
 | 
					        make_background_color<Char>(ts.get_background());
 | 
				
			||||||
 | 
					    buffer.append(escape.begin(), escape.end());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  internal::vformat_to(buffer, format_str, args);
 | 
				
			||||||
 | 
					  if (has_style) {
 | 
				
			||||||
 | 
					    reset_color<Char>(buffer);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return fmt::to_string(buffer);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}  // namespace internal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename S, typename Char = char_t<S> >
 | 
				
			||||||
 | 
					void vprint(std::FILE* f, const text_style& ts, const S& format,
 | 
				
			||||||
 | 
					            basic_format_args<buffer_context<Char> > args) {
 | 
				
			||||||
 | 
					  bool has_style = false;
 | 
				
			||||||
 | 
					  if (ts.has_emphasis()) {
 | 
				
			||||||
 | 
					    has_style = true;
 | 
				
			||||||
 | 
					    internal::fputs<Char>(internal::make_emphasis<Char>(ts.get_emphasis()), f);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (ts.has_foreground()) {
 | 
					  if (ts.has_foreground()) {
 | 
				
			||||||
    has_style = true;
 | 
					    has_style = true;
 | 
				
			||||||
@ -545,15 +531,14 @@ void vprint(std::FILE *f, const text_style &ts, const S &format,
 | 
				
			|||||||
    fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
 | 
					    fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
 | 
				
			||||||
               "Elapsed time: {0:.2f} seconds", 1.23);
 | 
					               "Elapsed time: {0:.2f} seconds", 1.23);
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
template <typename String, typename... Args>
 | 
					template <typename S, typename... Args,
 | 
				
			||||||
typename std::enable_if<internal::is_string<String>::value>::type print(
 | 
					          FMT_ENABLE_IF(internal::is_string<S>::value)>
 | 
				
			||||||
    std::FILE *f, const text_style &ts, const String &format_str,
 | 
					void print(std::FILE* f, const text_style& ts, const S& format_str,
 | 
				
			||||||
    const Args &... args) {
 | 
					           const Args&... args) {
 | 
				
			||||||
  internal::check_format_string<Args...>(format_str);
 | 
					  internal::check_format_string<Args...>(format_str);
 | 
				
			||||||
  typedef typename internal::char_t<String>::type char_t;
 | 
					  using context = buffer_context<char_t<S> >;
 | 
				
			||||||
  typedef typename buffer_context<char_t>::type context_t;
 | 
					  format_arg_store<context, Args...> as{args...};
 | 
				
			||||||
  format_arg_store<context_t, Args...> as{args...};
 | 
					  vprint(f, ts, format_str, basic_format_args<context>(as));
 | 
				
			||||||
  vprint(f, ts, format_str, basic_format_args<context_t>(as));
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -563,14 +548,37 @@ typename std::enable_if<internal::is_string<String>::value>::type print(
 | 
				
			|||||||
    fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
 | 
					    fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
 | 
				
			||||||
               "Elapsed time: {0:.2f} seconds", 1.23);
 | 
					               "Elapsed time: {0:.2f} seconds", 1.23);
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
template <typename String, typename... Args>
 | 
					template <typename S, typename... Args,
 | 
				
			||||||
typename std::enable_if<internal::is_string<String>::value>::type print(
 | 
					          FMT_ENABLE_IF(internal::is_string<S>::value)>
 | 
				
			||||||
    const text_style &ts, const String &format_str,
 | 
					void print(const text_style& ts, const S& format_str, const Args&... args) {
 | 
				
			||||||
    const Args &... args) {
 | 
					 | 
				
			||||||
  return print(stdout, ts, format_str, args...);
 | 
					  return print(stdout, ts, format_str, args...);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					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<Char> > args) {
 | 
				
			||||||
 | 
					  return internal::vformat(ts, to_string_view(format_str), args);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  \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 internal::vformat(ts, to_string_view(format_str),
 | 
				
			||||||
 | 
					                           {internal::make_args_checked(format_str, args...)});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FMT_END_NAMESPACE
 | 
					FMT_END_NAMESPACE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										466
									
								
								include/spdlog/fmt/bundled/compile.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										466
									
								
								include/spdlog/fmt/bundled/compile.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,466 @@
 | 
				
			|||||||
 | 
					// Formatting library for C++ - experimental format string compilation
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Copyright (c) 2012 - present, Victor Zverovich and fmt contributors
 | 
				
			||||||
 | 
					// All rights reserved.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// For the license information refer to format.h.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef FMT_COMPILE_H_
 | 
				
			||||||
 | 
					#define FMT_COMPILE_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include "format.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FMT_BEGIN_NAMESPACE
 | 
				
			||||||
 | 
					namespace internal {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Char> struct format_part {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  struct named_argument_id {
 | 
				
			||||||
 | 
					    FMT_CONSTEXPR named_argument_id(internal::string_view_metadata id)
 | 
				
			||||||
 | 
					        : id(id) {}
 | 
				
			||||||
 | 
					    internal::string_view_metadata id;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  struct argument_id {
 | 
				
			||||||
 | 
					    FMT_CONSTEXPR argument_id() : argument_id(0u) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FMT_CONSTEXPR argument_id(unsigned id)
 | 
				
			||||||
 | 
					        : which(which_arg_id::index), val(id) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FMT_CONSTEXPR argument_id(internal::string_view_metadata id)
 | 
				
			||||||
 | 
					        : which(which_arg_id::named_index), val(id) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    enum class which_arg_id { index, named_index };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    which_arg_id which;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    union value {
 | 
				
			||||||
 | 
					      FMT_CONSTEXPR value() : index(0u) {}
 | 
				
			||||||
 | 
					      FMT_CONSTEXPR value(unsigned id) : index(id) {}
 | 
				
			||||||
 | 
					      FMT_CONSTEXPR value(internal::string_view_metadata id)
 | 
				
			||||||
 | 
					          : named_index(id) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      unsigned index;
 | 
				
			||||||
 | 
					      internal::string_view_metadata named_index;
 | 
				
			||||||
 | 
					    } val;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  struct specification {
 | 
				
			||||||
 | 
					    FMT_CONSTEXPR specification() : arg_id(0u) {}
 | 
				
			||||||
 | 
					    FMT_CONSTEXPR specification(unsigned id) : arg_id(id) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FMT_CONSTEXPR specification(internal::string_view_metadata id)
 | 
				
			||||||
 | 
					        : arg_id(id) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    argument_id arg_id;
 | 
				
			||||||
 | 
					    internal::dynamic_format_specs<Char> parsed_specs;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR format_part()
 | 
				
			||||||
 | 
					      : which(kind::argument_id), end_of_argument_id(0u), val(0u) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR format_part(internal::string_view_metadata text)
 | 
				
			||||||
 | 
					      : which(kind::text), end_of_argument_id(0u), val(text) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR format_part(unsigned id)
 | 
				
			||||||
 | 
					      : which(kind::argument_id), end_of_argument_id(0u), val(id) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR format_part(named_argument_id arg_id)
 | 
				
			||||||
 | 
					      : which(kind::named_argument_id), end_of_argument_id(0u), val(arg_id) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR format_part(specification spec)
 | 
				
			||||||
 | 
					      : which(kind::specification), end_of_argument_id(0u), val(spec) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  enum class kind { argument_id, named_argument_id, text, specification };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  kind which;
 | 
				
			||||||
 | 
					  std::size_t end_of_argument_id;
 | 
				
			||||||
 | 
					  union value {
 | 
				
			||||||
 | 
					    FMT_CONSTEXPR value() : arg_id(0u) {}
 | 
				
			||||||
 | 
					    FMT_CONSTEXPR value(unsigned id) : arg_id(id) {}
 | 
				
			||||||
 | 
					    FMT_CONSTEXPR value(named_argument_id named_id)
 | 
				
			||||||
 | 
					        : named_arg_id(named_id.id) {}
 | 
				
			||||||
 | 
					    FMT_CONSTEXPR value(internal::string_view_metadata t) : text(t) {}
 | 
				
			||||||
 | 
					    FMT_CONSTEXPR value(specification s) : spec(s) {}
 | 
				
			||||||
 | 
					    unsigned arg_id;
 | 
				
			||||||
 | 
					    internal::string_view_metadata named_arg_id;
 | 
				
			||||||
 | 
					    internal::string_view_metadata text;
 | 
				
			||||||
 | 
					    specification spec;
 | 
				
			||||||
 | 
					  } val;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Char, typename PartsContainer>
 | 
				
			||||||
 | 
					class format_preparation_handler : public internal::error_handler {
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  using part = format_part<Char>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  using iterator = typename basic_string_view<Char>::iterator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR format_preparation_handler(basic_string_view<Char> format,
 | 
				
			||||||
 | 
					                                           PartsContainer& parts)
 | 
				
			||||||
 | 
					      : parts_(parts), format_(format), parse_context_(format) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
 | 
				
			||||||
 | 
					    if (begin == end) return;
 | 
				
			||||||
 | 
					    const auto offset = begin - format_.data();
 | 
				
			||||||
 | 
					    const auto size = end - begin;
 | 
				
			||||||
 | 
					    parts_.push_back(part(string_view_metadata(offset, size)));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR void on_arg_id() {
 | 
				
			||||||
 | 
					    parts_.push_back(part(parse_context_.next_arg_id()));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR void on_arg_id(unsigned id) {
 | 
				
			||||||
 | 
					    parse_context_.check_arg_id(id);
 | 
				
			||||||
 | 
					    parts_.push_back(part(id));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR void on_arg_id(basic_string_view<Char> id) {
 | 
				
			||||||
 | 
					    const auto view = string_view_metadata(format_, id);
 | 
				
			||||||
 | 
					    const auto arg_id = typename part::named_argument_id(view);
 | 
				
			||||||
 | 
					    parts_.push_back(part(arg_id));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR void on_replacement_field(const Char* ptr) {
 | 
				
			||||||
 | 
					    parts_.back().end_of_argument_id = ptr - format_.begin();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
 | 
				
			||||||
 | 
					                                            const Char* end) {
 | 
				
			||||||
 | 
					    const auto specs_offset = to_unsigned(begin - format_.begin());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    using parse_context = basic_parse_context<Char>;
 | 
				
			||||||
 | 
					    internal::dynamic_format_specs<Char> parsed_specs;
 | 
				
			||||||
 | 
					    dynamic_specs_handler<parse_context> handler(parsed_specs, parse_context_);
 | 
				
			||||||
 | 
					    begin = parse_format_specs(begin, end, handler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (*begin != '}') on_error("missing '}' in format string");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto& last_part = parts_.back();
 | 
				
			||||||
 | 
					    auto specs = last_part.which == part::kind::argument_id
 | 
				
			||||||
 | 
					                     ? typename part::specification(last_part.val.arg_id)
 | 
				
			||||||
 | 
					                     : typename part::specification(last_part.val.named_arg_id);
 | 
				
			||||||
 | 
					    specs.parsed_specs = parsed_specs;
 | 
				
			||||||
 | 
					    last_part = part(specs);
 | 
				
			||||||
 | 
					    last_part.end_of_argument_id = specs_offset;
 | 
				
			||||||
 | 
					    return begin;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  PartsContainer& parts_;
 | 
				
			||||||
 | 
					  basic_string_view<Char> format_;
 | 
				
			||||||
 | 
					  basic_parse_context<Char> parse_context_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Format, typename PreparedPartsProvider, typename... Args>
 | 
				
			||||||
 | 
					class prepared_format {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  using char_type = char_t<Format>;
 | 
				
			||||||
 | 
					  using format_part_t = format_part<char_type>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  constexpr prepared_format(Format f)
 | 
				
			||||||
 | 
					      : format_(std::move(f)), parts_provider_(to_string_view(format_)) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  prepared_format() = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  using context = buffer_context<char_type>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  template <typename Range, typename Context>
 | 
				
			||||||
 | 
					  auto vformat_to(Range out, basic_format_args<Context> args) const ->
 | 
				
			||||||
 | 
					      typename Context::iterator {
 | 
				
			||||||
 | 
					    const auto format_view = internal::to_string_view(format_);
 | 
				
			||||||
 | 
					    basic_parse_context<char_type> parse_ctx(format_view);
 | 
				
			||||||
 | 
					    Context ctx(out.begin(), args);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const auto& parts = parts_provider_.parts();
 | 
				
			||||||
 | 
					    for (auto part_it = parts.begin(); part_it != parts.end(); ++part_it) {
 | 
				
			||||||
 | 
					      const auto& part = *part_it;
 | 
				
			||||||
 | 
					      const auto& value = part.val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      switch (part.which) {
 | 
				
			||||||
 | 
					      case format_part_t::kind::text: {
 | 
				
			||||||
 | 
					        const auto text = value.text.to_view(format_view.data());
 | 
				
			||||||
 | 
					        auto output = ctx.out();
 | 
				
			||||||
 | 
					        auto&& it = internal::reserve(output, text.size());
 | 
				
			||||||
 | 
					        it = std::copy_n(text.begin(), text.size(), it);
 | 
				
			||||||
 | 
					        ctx.advance_to(output);
 | 
				
			||||||
 | 
					      } break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      case format_part_t::kind::argument_id: {
 | 
				
			||||||
 | 
					        advance_parse_context_to_specification(parse_ctx, part);
 | 
				
			||||||
 | 
					        format_arg<Range>(parse_ctx, ctx, value.arg_id);
 | 
				
			||||||
 | 
					      } break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      case format_part_t::kind::named_argument_id: {
 | 
				
			||||||
 | 
					        advance_parse_context_to_specification(parse_ctx, part);
 | 
				
			||||||
 | 
					        const auto named_arg_id =
 | 
				
			||||||
 | 
					            value.named_arg_id.to_view(format_view.data());
 | 
				
			||||||
 | 
					        format_arg<Range>(parse_ctx, ctx, named_arg_id);
 | 
				
			||||||
 | 
					      } break;
 | 
				
			||||||
 | 
					      case format_part_t::kind::specification: {
 | 
				
			||||||
 | 
					        const auto& arg_id_value = value.spec.arg_id.val;
 | 
				
			||||||
 | 
					        const auto arg = value.spec.arg_id.which ==
 | 
				
			||||||
 | 
					                                 format_part_t::argument_id::which_arg_id::index
 | 
				
			||||||
 | 
					                             ? ctx.arg(arg_id_value.index)
 | 
				
			||||||
 | 
					                             : ctx.arg(arg_id_value.named_index.to_view(
 | 
				
			||||||
 | 
					                                   to_string_view(format_).data()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto specs = value.spec.parsed_specs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        handle_dynamic_spec<internal::width_checker>(
 | 
				
			||||||
 | 
					            specs.width, specs.width_ref, ctx, format_view.begin());
 | 
				
			||||||
 | 
					        handle_dynamic_spec<internal::precision_checker>(
 | 
				
			||||||
 | 
					            specs.precision, specs.precision_ref, ctx, format_view.begin());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        check_prepared_specs(specs, arg.type());
 | 
				
			||||||
 | 
					        advance_parse_context_to_specification(parse_ctx, part);
 | 
				
			||||||
 | 
					        ctx.advance_to(
 | 
				
			||||||
 | 
					            visit_format_arg(arg_formatter<Range>(ctx, nullptr, &specs), arg));
 | 
				
			||||||
 | 
					      } break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ctx.out();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  void advance_parse_context_to_specification(
 | 
				
			||||||
 | 
					      basic_parse_context<char_type>& parse_ctx,
 | 
				
			||||||
 | 
					      const format_part_t& part) const {
 | 
				
			||||||
 | 
					    const auto view = to_string_view(format_);
 | 
				
			||||||
 | 
					    const auto specification_begin = view.data() + part.end_of_argument_id;
 | 
				
			||||||
 | 
					    advance_to(parse_ctx, specification_begin);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  template <typename Range, typename Context, typename Id>
 | 
				
			||||||
 | 
					  void format_arg(basic_parse_context<char_type>& parse_ctx, Context& ctx,
 | 
				
			||||||
 | 
					                  Id arg_id) const {
 | 
				
			||||||
 | 
					    parse_ctx.check_arg_id(arg_id);
 | 
				
			||||||
 | 
					    const auto stopped_at =
 | 
				
			||||||
 | 
					        visit_format_arg(arg_formatter<Range>(ctx), ctx.arg(arg_id));
 | 
				
			||||||
 | 
					    ctx.advance_to(stopped_at);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  template <typename Char>
 | 
				
			||||||
 | 
					  void check_prepared_specs(const basic_format_specs<Char>& specs,
 | 
				
			||||||
 | 
					                            internal::type arg_type) const {
 | 
				
			||||||
 | 
					    internal::error_handler h;
 | 
				
			||||||
 | 
					    numeric_specs_checker<internal::error_handler> checker(h, arg_type);
 | 
				
			||||||
 | 
					    if (specs.align == align::numeric) checker.require_numeric_argument();
 | 
				
			||||||
 | 
					    if (specs.sign != sign::none) checker.check_sign();
 | 
				
			||||||
 | 
					    if (specs.alt) checker.require_numeric_argument();
 | 
				
			||||||
 | 
					    if (specs.precision >= 0) checker.check_precision();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  Format format_;
 | 
				
			||||||
 | 
					  PreparedPartsProvider parts_provider_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Char> struct part_counter {
 | 
				
			||||||
 | 
					  unsigned num_parts = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
 | 
				
			||||||
 | 
					    if (begin != end) ++num_parts;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR void on_arg_id() { ++num_parts; }
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR void on_arg_id(unsigned) { ++num_parts; }
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR void on_arg_id(basic_string_view<Char>) { ++num_parts; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR void on_replacement_field(const Char*) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
 | 
				
			||||||
 | 
					                                            const Char* end) {
 | 
				
			||||||
 | 
					    // Find the matching brace.
 | 
				
			||||||
 | 
					    unsigned braces_counter = 0;
 | 
				
			||||||
 | 
					    for (; begin != end; ++begin) {
 | 
				
			||||||
 | 
					      if (*begin == '{') {
 | 
				
			||||||
 | 
					        ++braces_counter;
 | 
				
			||||||
 | 
					      } else if (*begin == '}') {
 | 
				
			||||||
 | 
					        if (braces_counter == 0u) break;
 | 
				
			||||||
 | 
					        --braces_counter;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return begin;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR void on_error(const char*) {}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Format> class compiletime_prepared_parts_type_provider {
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  using char_type = char_t<Format>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static FMT_CONSTEXPR unsigned count_parts() {
 | 
				
			||||||
 | 
					    FMT_CONSTEXPR_DECL const auto text = to_string_view(Format{});
 | 
				
			||||||
 | 
					    part_counter<char_type> counter;
 | 
				
			||||||
 | 
					    internal::parse_format_string</*IS_CONSTEXPR=*/true>(text, counter);
 | 
				
			||||||
 | 
					    return counter.num_parts;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Workaround for old compilers. Compiletime parts preparation will not be
 | 
				
			||||||
 | 
					// performed with them anyway.
 | 
				
			||||||
 | 
					#if FMT_USE_CONSTEXPR
 | 
				
			||||||
 | 
					  static FMT_CONSTEXPR_DECL const unsigned number_of_format_parts =
 | 
				
			||||||
 | 
					      compiletime_prepared_parts_type_provider::count_parts();
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					  static const unsigned number_of_format_parts = 0u;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  template <unsigned N> struct format_parts_array {
 | 
				
			||||||
 | 
					    using value_type = format_part<char_type>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FMT_CONSTEXPR format_parts_array() : arr{} {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FMT_CONSTEXPR value_type& operator[](unsigned ind) { return arr[ind]; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FMT_CONSTEXPR const value_type* begin() const { return arr; }
 | 
				
			||||||
 | 
					    FMT_CONSTEXPR const value_type* end() const { return begin() + N; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   private:
 | 
				
			||||||
 | 
					    value_type arr[N];
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  struct empty {
 | 
				
			||||||
 | 
					    // Parts preparator will search for it
 | 
				
			||||||
 | 
					    using value_type = format_part<char_type>;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  using type = conditional_t<number_of_format_parts != 0,
 | 
				
			||||||
 | 
					                             format_parts_array<number_of_format_parts>, empty>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Parts> class compiletime_prepared_parts_collector {
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  using format_part = typename Parts::value_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR explicit compiletime_prepared_parts_collector(Parts& parts)
 | 
				
			||||||
 | 
					      : parts_{parts}, counter_{0u} {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR void push_back(format_part part) { parts_[counter_++] = part; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR format_part& back() { return parts_[counter_ - 1]; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  Parts& parts_;
 | 
				
			||||||
 | 
					  unsigned counter_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename PartsContainer, typename Char>
 | 
				
			||||||
 | 
					FMT_CONSTEXPR PartsContainer prepare_parts(basic_string_view<Char> format) {
 | 
				
			||||||
 | 
					  PartsContainer parts;
 | 
				
			||||||
 | 
					  internal::parse_format_string</*IS_CONSTEXPR=*/false>(
 | 
				
			||||||
 | 
					      format, format_preparation_handler<Char, PartsContainer>(format, parts));
 | 
				
			||||||
 | 
					  return parts;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename PartsContainer, typename Char>
 | 
				
			||||||
 | 
					FMT_CONSTEXPR PartsContainer
 | 
				
			||||||
 | 
					prepare_compiletime_parts(basic_string_view<Char> format) {
 | 
				
			||||||
 | 
					  using collector = compiletime_prepared_parts_collector<PartsContainer>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PartsContainer parts;
 | 
				
			||||||
 | 
					  collector c(parts);
 | 
				
			||||||
 | 
					  internal::parse_format_string</*IS_CONSTEXPR=*/true>(
 | 
				
			||||||
 | 
					      format, format_preparation_handler<Char, collector>(format, c));
 | 
				
			||||||
 | 
					  return parts;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename PartsContainer> class runtime_parts_provider {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  runtime_parts_provider() = delete;
 | 
				
			||||||
 | 
					  template <typename Char>
 | 
				
			||||||
 | 
					  runtime_parts_provider(basic_string_view<Char> format)
 | 
				
			||||||
 | 
					      : parts_(prepare_parts<PartsContainer>(format)) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const PartsContainer& parts() const { return parts_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  PartsContainer parts_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename Format, typename PartsContainer>
 | 
				
			||||||
 | 
					struct compiletime_parts_provider {
 | 
				
			||||||
 | 
					  compiletime_parts_provider() = delete;
 | 
				
			||||||
 | 
					  template <typename Char>
 | 
				
			||||||
 | 
					  FMT_CONSTEXPR compiletime_parts_provider(basic_string_view<Char>) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const PartsContainer& parts() const {
 | 
				
			||||||
 | 
					    static FMT_CONSTEXPR_DECL const PartsContainer prepared_parts =
 | 
				
			||||||
 | 
					        prepare_compiletime_parts<PartsContainer>(
 | 
				
			||||||
 | 
					            internal::to_string_view(Format{}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return prepared_parts;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					}  // namespace internal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if FMT_USE_CONSTEXPR
 | 
				
			||||||
 | 
					template <typename... Args, typename S,
 | 
				
			||||||
 | 
					          FMT_ENABLE_IF(is_compile_string<S>::value)>
 | 
				
			||||||
 | 
					FMT_CONSTEXPR auto compile(S format_str) -> internal::prepared_format<
 | 
				
			||||||
 | 
					    S,
 | 
				
			||||||
 | 
					    internal::compiletime_parts_provider<
 | 
				
			||||||
 | 
					        S,
 | 
				
			||||||
 | 
					        typename internal::compiletime_prepared_parts_type_provider<S>::type>,
 | 
				
			||||||
 | 
					    Args...> {
 | 
				
			||||||
 | 
					  return format_str;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename... Args, typename Char, size_t N>
 | 
				
			||||||
 | 
					auto compile(const Char (&format_str)[N]) -> internal::prepared_format<
 | 
				
			||||||
 | 
					    std::basic_string<Char>,
 | 
				
			||||||
 | 
					    internal::runtime_parts_provider<std::vector<internal::format_part<Char>>>,
 | 
				
			||||||
 | 
					    Args...> {
 | 
				
			||||||
 | 
					  return std::basic_string<Char>(format_str, N - 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename CompiledFormat, typename... Args,
 | 
				
			||||||
 | 
					          typename Char = typename CompiledFormat::char_type>
 | 
				
			||||||
 | 
					std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
 | 
				
			||||||
 | 
					  basic_memory_buffer<Char> buffer;
 | 
				
			||||||
 | 
					  using range = internal::buffer_range<Char>;
 | 
				
			||||||
 | 
					  using context = buffer_context<Char>;
 | 
				
			||||||
 | 
					  cf.template vformat_to<range, context>(range(buffer),
 | 
				
			||||||
 | 
					                                         {make_format_args<context>(args...)});
 | 
				
			||||||
 | 
					  return to_string(buffer);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename OutputIt, typename CompiledFormat, typename... Args>
 | 
				
			||||||
 | 
					OutputIt format_to(OutputIt out, const CompiledFormat& cf,
 | 
				
			||||||
 | 
					                   const Args&... args) {
 | 
				
			||||||
 | 
					  using char_type = typename CompiledFormat::char_type;
 | 
				
			||||||
 | 
					  using range = internal::output_range<OutputIt, char_type>;
 | 
				
			||||||
 | 
					  using context = format_context_t<OutputIt, char_type>;
 | 
				
			||||||
 | 
					  return cf.template vformat_to<range, context>(
 | 
				
			||||||
 | 
					      range(out), {make_format_args<context>(args...)});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename OutputIt, typename CompiledFormat, typename... Args,
 | 
				
			||||||
 | 
					          FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value)>
 | 
				
			||||||
 | 
					format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
 | 
				
			||||||
 | 
					                                         const CompiledFormat& cf,
 | 
				
			||||||
 | 
					                                         const Args&... args) {
 | 
				
			||||||
 | 
					  auto it =
 | 
				
			||||||
 | 
					      format_to(internal::truncating_iterator<OutputIt>(out, n), cf, args...);
 | 
				
			||||||
 | 
					  return {it.base(), it.count()};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename CompiledFormat, typename... Args>
 | 
				
			||||||
 | 
					std::size_t formatted_size(const CompiledFormat& cf, const Args&... args) {
 | 
				
			||||||
 | 
					  return fmt::format_to(
 | 
				
			||||||
 | 
					             internal::counting_iterator<typename CompiledFormat::char_type>(),
 | 
				
			||||||
 | 
					             cf, args...)
 | 
				
			||||||
 | 
					      .count();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FMT_END_NAMESPACE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  // FMT_COMPILE_H_
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -8,65 +8,65 @@
 | 
				
			|||||||
#ifndef FMT_LOCALE_H_
 | 
					#ifndef FMT_LOCALE_H_
 | 
				
			||||||
#define FMT_LOCALE_H_
 | 
					#define FMT_LOCALE_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "format.h"
 | 
					 | 
				
			||||||
#include <locale>
 | 
					#include <locale>
 | 
				
			||||||
 | 
					#include "format.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FMT_BEGIN_NAMESPACE
 | 
					FMT_BEGIN_NAMESPACE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace internal {
 | 
					namespace internal {
 | 
				
			||||||
template <typename Char>
 | 
					template <typename Char>
 | 
				
			||||||
typename buffer_context<Char>::type::iterator vformat_to(
 | 
					typename buffer_context<Char>::iterator vformat_to(
 | 
				
			||||||
    const std::locale &loc, basic_buffer<Char> &buf,
 | 
					    const std::locale& loc, buffer<Char>& buf,
 | 
				
			||||||
    basic_string_view<Char> format_str,
 | 
					    basic_string_view<Char> format_str,
 | 
				
			||||||
    basic_format_args<typename buffer_context<Char>::type> args) {
 | 
					    basic_format_args<buffer_context<Char>> args) {
 | 
				
			||||||
  typedef back_insert_range<basic_buffer<Char> > range;
 | 
					  using range = buffer_range<Char>;
 | 
				
			||||||
  return vformat_to<arg_formatter<range>>(
 | 
					  return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str), args,
 | 
				
			||||||
    buf, to_string_view(format_str), args, internal::locale_ref(loc));
 | 
					                                          internal::locale_ref(loc));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename Char>
 | 
					template <typename Char>
 | 
				
			||||||
std::basic_string<Char> vformat(
 | 
					std::basic_string<Char> vformat(const std::locale& loc,
 | 
				
			||||||
    const std::locale &loc, basic_string_view<Char> format_str,
 | 
					                                basic_string_view<Char> format_str,
 | 
				
			||||||
    basic_format_args<typename buffer_context<Char>::type> args) {
 | 
					                                basic_format_args<buffer_context<Char>> args) {
 | 
				
			||||||
  basic_memory_buffer<Char> buffer;
 | 
					  basic_memory_buffer<Char> buffer;
 | 
				
			||||||
  internal::vformat_to(loc, buffer, format_str, args);
 | 
					  internal::vformat_to(loc, buffer, format_str, args);
 | 
				
			||||||
  return fmt::to_string(buffer);
 | 
					  return fmt::to_string(buffer);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}
 | 
					}  // namespace internal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename S, typename Char = FMT_CHAR(S)>
 | 
					template <typename S, typename Char = char_t<S>>
 | 
				
			||||||
inline std::basic_string<Char> vformat(
 | 
					inline std::basic_string<Char> vformat(
 | 
				
			||||||
    const std::locale &loc, const S &format_str,
 | 
					    const std::locale& loc, const S& format_str,
 | 
				
			||||||
    basic_format_args<typename buffer_context<Char>::type> args) {
 | 
					    basic_format_args<buffer_context<Char>> args) {
 | 
				
			||||||
  return internal::vformat(loc, to_string_view(format_str), args);
 | 
					  return internal::vformat(loc, to_string_view(format_str), args);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename S, typename... Args>
 | 
					template <typename S, typename... Args, typename Char = char_t<S>>
 | 
				
			||||||
inline std::basic_string<FMT_CHAR(S)> format(
 | 
					inline std::basic_string<Char> format(const std::locale& loc,
 | 
				
			||||||
    const std::locale &loc, const S &format_str, const Args &... args) {
 | 
					                                      const S& format_str, Args&&... args) {
 | 
				
			||||||
  return internal::vformat(
 | 
					  return internal::vformat(
 | 
				
			||||||
      loc, to_string_view(format_str),
 | 
					      loc, to_string_view(format_str),
 | 
				
			||||||
    *internal::checked_args<S, Args...>(format_str, args...));
 | 
					      {internal::make_args_checked<Args...>(format_str, args...)});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename String, typename OutputIt, typename... Args>
 | 
					template <typename S, typename OutputIt, typename... Args,
 | 
				
			||||||
inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value,
 | 
					          typename Char = enable_if_t<
 | 
				
			||||||
                               OutputIt>::type
 | 
					              internal::is_output_iterator<OutputIt>::value, char_t<S>>>
 | 
				
			||||||
    vformat_to(OutputIt out, const std::locale &loc, const String &format_str,
 | 
					inline OutputIt vformat_to(OutputIt out, const std::locale& loc,
 | 
				
			||||||
               typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) {
 | 
					                           const S& format_str,
 | 
				
			||||||
  typedef output_range<OutputIt, FMT_CHAR(String)> range;
 | 
					                           format_args_t<OutputIt, Char> args) {
 | 
				
			||||||
 | 
					  using range = internal::output_range<OutputIt, Char>;
 | 
				
			||||||
  return vformat_to<arg_formatter<range>>(
 | 
					  return vformat_to<arg_formatter<range>>(
 | 
				
			||||||
      range(out), to_string_view(format_str), args, internal::locale_ref(loc));
 | 
					      range(out), to_string_view(format_str), args, internal::locale_ref(loc));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename OutputIt, typename S, typename... Args>
 | 
					template <typename OutputIt, typename S, typename... Args,
 | 
				
			||||||
inline typename std::enable_if<
 | 
					          FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value&&
 | 
				
			||||||
    internal::is_string<S>::value &&
 | 
					                            internal::is_string<S>::value)>
 | 
				
			||||||
    internal::is_output_iterator<OutputIt>::value, OutputIt>::type
 | 
					inline OutputIt format_to(OutputIt out, const std::locale& loc,
 | 
				
			||||||
    format_to(OutputIt out, const std::locale &loc, const S &format_str,
 | 
					                          const S& format_str, Args&&... args) {
 | 
				
			||||||
              const Args &... args) {
 | 
					 | 
				
			||||||
  internal::check_format_string<Args...>(format_str);
 | 
					  internal::check_format_string<Args...>(format_str);
 | 
				
			||||||
  typedef typename format_context_t<OutputIt, FMT_CHAR(S)>::type context;
 | 
					  using context = format_context_t<OutputIt, char_t<S>>;
 | 
				
			||||||
  format_arg_store<context, Args...> as{args...};
 | 
					  format_arg_store<context, Args...> as{args...};
 | 
				
			||||||
  return vformat_to(out, loc, to_string_view(format_str),
 | 
					  return vformat_to(out, loc, to_string_view(format_str),
 | 
				
			||||||
                    basic_format_args<context>(as));
 | 
					                    basic_format_args<context>(as));
 | 
				
			||||||
 | 
				
			|||||||
@ -8,22 +8,21 @@
 | 
				
			|||||||
#ifndef FMT_OSTREAM_H_
 | 
					#ifndef FMT_OSTREAM_H_
 | 
				
			||||||
#define FMT_OSTREAM_H_
 | 
					#define FMT_OSTREAM_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "format.h"
 | 
					 | 
				
			||||||
#include <ostream>
 | 
					#include <ostream>
 | 
				
			||||||
 | 
					#include "format.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FMT_BEGIN_NAMESPACE
 | 
					FMT_BEGIN_NAMESPACE
 | 
				
			||||||
namespace internal {
 | 
					namespace internal {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <class Char>
 | 
					template <class Char> class formatbuf : public std::basic_streambuf<Char> {
 | 
				
			||||||
class formatbuf : public std::basic_streambuf<Char> {
 | 
					 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  typedef typename std::basic_streambuf<Char>::int_type int_type;
 | 
					  using int_type = typename std::basic_streambuf<Char>::int_type;
 | 
				
			||||||
  typedef typename std::basic_streambuf<Char>::traits_type traits_type;
 | 
					  using traits_type = typename std::basic_streambuf<Char>::traits_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  basic_buffer<Char> &buffer_;
 | 
					  buffer<Char>& buffer_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  formatbuf(basic_buffer<Char> &buffer) : buffer_(buffer) {}
 | 
					  formatbuf(buffer<Char>& buf) : buffer_(buf) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 protected:
 | 
					 protected:
 | 
				
			||||||
  // The put-area is actually always empty. This makes the implementation
 | 
					  // The put-area is actually always empty. This makes the implementation
 | 
				
			||||||
@ -39,33 +38,32 @@ class formatbuf : public std::basic_streambuf<Char> {
 | 
				
			|||||||
    return ch;
 | 
					    return ch;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE {
 | 
					  std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE {
 | 
				
			||||||
    buffer_.append(s, s + count);
 | 
					    buffer_.append(s, s + count);
 | 
				
			||||||
    return count;
 | 
					    return count;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename Char>
 | 
					template <typename Char> struct test_stream : std::basic_ostream<Char> {
 | 
				
			||||||
struct test_stream : std::basic_ostream<Char> {
 | 
					 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  struct null;
 | 
					  struct null;
 | 
				
			||||||
  // Hide all operator<< from std::basic_ostream<Char>.
 | 
					  // Hide all operator<< from std::basic_ostream<Char>.
 | 
				
			||||||
  void operator<<(null);
 | 
					  void operator<<(null);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Checks if T has a user-defined operator<< (e.g. not a member of std::ostream).
 | 
					// Checks if T has a user-defined operator<< (e.g. not a member of
 | 
				
			||||||
template <typename T, typename Char>
 | 
					// std::ostream).
 | 
				
			||||||
class is_streamable {
 | 
					template <typename T, typename Char> class is_streamable {
 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  template <typename U>
 | 
					  template <typename U>
 | 
				
			||||||
  static decltype(
 | 
					  static decltype((void)(std::declval<test_stream<Char>&>()
 | 
				
			||||||
    internal::declval<test_stream<Char>&>()
 | 
					                         << std::declval<U>()),
 | 
				
			||||||
      << internal::declval<U>(), std::true_type()) test(int);
 | 
					                  std::true_type())
 | 
				
			||||||
 | 
					  test(int);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template <typename>
 | 
					  template <typename> static std::false_type test(...);
 | 
				
			||||||
  static std::false_type test(...);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  typedef decltype(test<T>(0)) result;
 | 
					  using result = decltype(test<T>(0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  static const bool value = result::value;
 | 
					  static const bool value = result::value;
 | 
				
			||||||
@ -73,65 +71,51 @@ class is_streamable {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Write the content of buf to os.
 | 
					// Write the content of buf to os.
 | 
				
			||||||
template <typename Char>
 | 
					template <typename Char>
 | 
				
			||||||
void write(std::basic_ostream<Char> &os, basic_buffer<Char> &buf) {
 | 
					void write(std::basic_ostream<Char>& os, buffer<Char>& buf) {
 | 
				
			||||||
  const Char *data = buf.data();
 | 
					  const Char* buf_data = buf.data();
 | 
				
			||||||
  typedef std::make_unsigned<std::streamsize>::type UnsignedStreamSize;
 | 
					  using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
 | 
				
			||||||
  UnsignedStreamSize size = buf.size();
 | 
					  unsigned_streamsize size = buf.size();
 | 
				
			||||||
  UnsignedStreamSize max_size =
 | 
					  unsigned_streamsize max_size =
 | 
				
			||||||
      internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
 | 
					      to_unsigned((std::numeric_limits<std::streamsize>::max)());
 | 
				
			||||||
  do {
 | 
					  do {
 | 
				
			||||||
    UnsignedStreamSize n = size <= max_size ? size : max_size;
 | 
					    unsigned_streamsize n = size <= max_size ? size : max_size;
 | 
				
			||||||
    os.write(data, static_cast<std::streamsize>(n));
 | 
					    os.write(buf_data, static_cast<std::streamsize>(n));
 | 
				
			||||||
    data += n;
 | 
					    buf_data += n;
 | 
				
			||||||
    size -= n;
 | 
					    size -= n;
 | 
				
			||||||
  } while (size != 0);
 | 
					  } while (size != 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename Char, typename T>
 | 
					template <typename Char, typename T>
 | 
				
			||||||
void format_value(basic_buffer<Char> &buffer, const T &value) {
 | 
					void format_value(buffer<Char>& buf, const T& value) {
 | 
				
			||||||
  internal::formatbuf<Char> format_buf(buffer);
 | 
					  formatbuf<Char> format_buf(buf);
 | 
				
			||||||
  std::basic_ostream<Char> output(&format_buf);
 | 
					  std::basic_ostream<Char> output(&format_buf);
 | 
				
			||||||
  output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
 | 
					  output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
 | 
				
			||||||
  output << value;
 | 
					  output << value;
 | 
				
			||||||
  buffer.resize(buffer.size());
 | 
					  buf.resize(buf.size());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}  // namespace internal
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Disable conversion to int if T has an overloaded operator<< which is a free
 | 
					 | 
				
			||||||
// function (not a member of std::ostream).
 | 
					 | 
				
			||||||
template <typename T, typename Char>
 | 
					 | 
				
			||||||
struct convert_to_int<T, Char, void> {
 | 
					 | 
				
			||||||
  static const bool value =
 | 
					 | 
				
			||||||
    convert_to_int<T, Char, int>::value &&
 | 
					 | 
				
			||||||
    !internal::is_streamable<T, Char>::value;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Formats an object of type T that has an overloaded ostream operator<<.
 | 
					// Formats an object of type T that has an overloaded ostream operator<<.
 | 
				
			||||||
template <typename T, typename Char>
 | 
					template <typename T, typename Char>
 | 
				
			||||||
struct formatter<T, Char,
 | 
					struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
 | 
				
			||||||
    typename std::enable_if<
 | 
					 | 
				
			||||||
      internal::is_streamable<T, Char>::value &&
 | 
					 | 
				
			||||||
      !internal::format_type<
 | 
					 | 
				
			||||||
        typename buffer_context<Char>::type, T>::value>::type>
 | 
					 | 
				
			||||||
    : formatter<basic_string_view<Char>, Char> {
 | 
					    : formatter<basic_string_view<Char>, Char> {
 | 
				
			||||||
 | 
					 | 
				
			||||||
  template <typename Context>
 | 
					  template <typename Context>
 | 
				
			||||||
  auto format(const T &value, Context &ctx) -> decltype(ctx.out()) {
 | 
					  auto format(const T& value, Context& ctx) -> decltype(ctx.out()) {
 | 
				
			||||||
    basic_memory_buffer<Char> buffer;
 | 
					    basic_memory_buffer<Char> buffer;
 | 
				
			||||||
    internal::format_value(buffer, value);
 | 
					    format_value(buffer, value);
 | 
				
			||||||
    basic_string_view<Char> str(buffer.data(), buffer.size());
 | 
					    basic_string_view<Char> str(buffer.data(), buffer.size());
 | 
				
			||||||
    return formatter<basic_string_view<Char>, Char>::format(str, ctx);
 | 
					    return formatter<basic_string_view<Char>, Char>::format(str, ctx);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					}  // namespace internal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename Char>
 | 
					template <typename Char>
 | 
				
			||||||
inline void vprint(std::basic_ostream<Char> &os,
 | 
					void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
 | 
				
			||||||
                   basic_string_view<Char> format_str,
 | 
					            basic_format_args<buffer_context<Char>> args) {
 | 
				
			||||||
                   basic_format_args<typename buffer_context<Char>::type> args) {
 | 
					 | 
				
			||||||
  basic_memory_buffer<Char> buffer;
 | 
					  basic_memory_buffer<Char> buffer;
 | 
				
			||||||
  internal::vformat_to(buffer, format_str, args);
 | 
					  internal::vformat_to(buffer, format_str, args);
 | 
				
			||||||
  internal::write(os, buffer);
 | 
					  internal::write(os, buffer);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
  \rst
 | 
					  \rst
 | 
				
			||||||
  Prints formatted data to the stream *os*.
 | 
					  Prints formatted data to the stream *os*.
 | 
				
			||||||
@ -141,12 +125,11 @@ inline void vprint(std::basic_ostream<Char> &os,
 | 
				
			|||||||
    fmt::print(cerr, "Don't {}!", "panic");
 | 
					    fmt::print(cerr, "Don't {}!", "panic");
 | 
				
			||||||
  \endrst
 | 
					  \endrst
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
template <typename S, typename... Args>
 | 
					template <typename S, typename... Args,
 | 
				
			||||||
inline typename std::enable_if<internal::is_string<S>::value>::type
 | 
					          typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
 | 
				
			||||||
print(std::basic_ostream<FMT_CHAR(S)> &os, const S &format_str,
 | 
					void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
 | 
				
			||||||
      const Args & ... args) {
 | 
					  vprint(os, to_string_view(format_str),
 | 
				
			||||||
  internal::checked_args<S, Args...> ca(format_str, args...);
 | 
					         {internal::make_args_checked<Args...>(format_str, args...)});
 | 
				
			||||||
  vprint(os, to_string_view(format_str), *ca);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
FMT_END_NAMESPACE
 | 
					FMT_END_NAMESPACE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -69,7 +69,7 @@ FMT_BEGIN_NAMESPACE
 | 
				
			|||||||
  A reference to a null-terminated string. It can be constructed from a C
 | 
					  A reference to a null-terminated string. It can be constructed from a C
 | 
				
			||||||
  string or ``std::string``.
 | 
					  string or ``std::string``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  You can use one of the following typedefs for common character types:
 | 
					  You can use one of the following type aliases for common character types:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  +---------------+-----------------------------+
 | 
					  +---------------+-----------------------------+
 | 
				
			||||||
  | Type          | Definition                  |
 | 
					  | Type          | Definition                  |
 | 
				
			||||||
@ -89,28 +89,27 @@ FMT_BEGIN_NAMESPACE
 | 
				
			|||||||
    format(std::string("{}"), 42);
 | 
					    format(std::string("{}"), 42);
 | 
				
			||||||
  \endrst
 | 
					  \endrst
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
template <typename Char>
 | 
					template <typename Char> class basic_cstring_view {
 | 
				
			||||||
class basic_cstring_view {
 | 
					 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  const Char *data_;
 | 
					  const Char* data_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 public:
 | 
					 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) {}
 | 
					  basic_cstring_view(const Char* s) : data_(s) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
    \rst
 | 
					    \rst
 | 
				
			||||||
    Constructs a string reference from an ``std::string`` object.
 | 
					    Constructs a string reference from an ``std::string`` object.
 | 
				
			||||||
    \endrst
 | 
					    \endrst
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  basic_cstring_view(const std::basic_string<Char> &s) : data_(s.c_str()) {}
 | 
					  basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Returns the pointer to a C string. */
 | 
					  /** Returns the pointer to a C string. */
 | 
				
			||||||
  const Char *c_str() const { return data_; }
 | 
					  const Char* c_str() const { return data_; }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef basic_cstring_view<char> cstring_view;
 | 
					using cstring_view = basic_cstring_view<char>;
 | 
				
			||||||
typedef basic_cstring_view<wchar_t> wcstring_view;
 | 
					using wcstring_view = basic_cstring_view<wchar_t>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// An error code.
 | 
					// An error code.
 | 
				
			||||||
class error_code {
 | 
					class error_code {
 | 
				
			||||||
@ -126,33 +125,32 @@ class error_code {
 | 
				
			|||||||
// A buffered file.
 | 
					// A buffered file.
 | 
				
			||||||
class buffered_file {
 | 
					class buffered_file {
 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  FILE *file_;
 | 
					  FILE* file_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  friend class file;
 | 
					  friend class file;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  explicit buffered_file(FILE *f) : file_(f) {}
 | 
					  explicit buffered_file(FILE* f) : file_(f) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  // Constructs a buffered_file object which doesn't represent any file.
 | 
					  // Constructs a buffered_file object which doesn't represent any file.
 | 
				
			||||||
  buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {}
 | 
					  buffered_file() FMT_NOEXCEPT : file_(nullptr) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Destroys the object closing the file it represents if any.
 | 
					  // Destroys the object closing the file it represents if any.
 | 
				
			||||||
  FMT_API ~buffered_file() FMT_NOEXCEPT;
 | 
					  FMT_API ~buffered_file() FMT_NOEXCEPT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  buffered_file(const buffered_file &) = delete;
 | 
					  buffered_file(const buffered_file&) = delete;
 | 
				
			||||||
  void operator=(const buffered_file &) = delete;
 | 
					  void operator=(const buffered_file&) = delete;
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  buffered_file(buffered_file &&other) FMT_NOEXCEPT : file_(other.file_) {
 | 
					  buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
 | 
				
			||||||
    other.file_ = FMT_NULL;
 | 
					    other.file_ = nullptr;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  buffered_file& operator=(buffered_file &&other) {
 | 
					  buffered_file& operator=(buffered_file&& other) {
 | 
				
			||||||
    close();
 | 
					    close();
 | 
				
			||||||
    file_ = other.file_;
 | 
					    file_ = other.file_;
 | 
				
			||||||
    other.file_ = FMT_NULL;
 | 
					    other.file_ = nullptr;
 | 
				
			||||||
    return *this;
 | 
					    return *this;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -163,18 +161,18 @@ class buffered_file {
 | 
				
			|||||||
  FMT_API void close();
 | 
					  FMT_API void close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Returns the pointer to a FILE object representing this file.
 | 
					  // Returns the pointer to a FILE object representing this file.
 | 
				
			||||||
  FILE *get() const FMT_NOEXCEPT { return file_; }
 | 
					  FILE* get() const FMT_NOEXCEPT { return file_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // We place parentheses around fileno to workaround a bug in some versions
 | 
					  // We place parentheses around fileno to workaround a bug in some versions
 | 
				
			||||||
  // of MinGW that define fileno as a macro.
 | 
					  // of MinGW that define fileno as a macro.
 | 
				
			||||||
  FMT_API int (fileno)() const;
 | 
					  FMT_API int(fileno)() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void vprint(string_view format_str, format_args args) {
 | 
					  void vprint(string_view format_str, format_args args) {
 | 
				
			||||||
    fmt::vprint(file_, format_str, args);
 | 
					    fmt::vprint(file_, format_str, args);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template <typename... Args>
 | 
					  template <typename... Args>
 | 
				
			||||||
  inline void print(string_view format_str, const Args & ... args) {
 | 
					  inline void print(string_view format_str, const Args&... args) {
 | 
				
			||||||
    vprint(format_str, make_format_args(args...));
 | 
					    vprint(format_str, make_format_args(args...));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -207,15 +205,13 @@ class file {
 | 
				
			|||||||
  FMT_API file(cstring_view path, int oflag);
 | 
					  FMT_API file(cstring_view path, int oflag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  file(const file &) = delete;
 | 
					  file(const file&) = delete;
 | 
				
			||||||
  void operator=(const file &) = delete;
 | 
					  void operator=(const file&) = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  file(file &&other) FMT_NOEXCEPT : fd_(other.fd_) {
 | 
					  file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; }
 | 
				
			||||||
    other.fd_ = -1;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  file& operator=(file &&other) {
 | 
					  file& operator=(file&& other) {
 | 
				
			||||||
    close();
 | 
					    close();
 | 
				
			||||||
    fd_ = other.fd_;
 | 
					    fd_ = other.fd_;
 | 
				
			||||||
    other.fd_ = -1;
 | 
					    other.fd_ = -1;
 | 
				
			||||||
@ -236,10 +232,10 @@ class file {
 | 
				
			|||||||
  FMT_API long long size() const;
 | 
					  FMT_API long long size() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Attempts to read count bytes from the file into the specified buffer.
 | 
					  // Attempts to read count bytes from the file into the specified buffer.
 | 
				
			||||||
  FMT_API std::size_t read(void *buffer, std::size_t count);
 | 
					  FMT_API std::size_t read(void* buffer, std::size_t count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Attempts to write count bytes from the specified buffer to the file.
 | 
					  // Attempts to write count bytes from the specified buffer to the file.
 | 
				
			||||||
  FMT_API std::size_t write(const void *buffer, std::size_t count);
 | 
					  FMT_API std::size_t write(const void* buffer, std::size_t count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Duplicates a file descriptor with the dup function and returns
 | 
					  // Duplicates a file descriptor with the dup function and returns
 | 
				
			||||||
  // the duplicate as a file object.
 | 
					  // the duplicate as a file object.
 | 
				
			||||||
@ -251,68 +247,59 @@ class file {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // Makes fd be the copy of this file descriptor, closing fd first if
 | 
					  // Makes fd be the copy of this file descriptor, closing fd first if
 | 
				
			||||||
  // necessary.
 | 
					  // necessary.
 | 
				
			||||||
  FMT_API void dup2(int fd, error_code &ec) FMT_NOEXCEPT;
 | 
					  FMT_API void dup2(int fd, error_code& ec) FMT_NOEXCEPT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Creates a pipe setting up read_end and write_end file objects for reading
 | 
					  // Creates a pipe setting up read_end and write_end file objects for reading
 | 
				
			||||||
  // and writing respectively.
 | 
					  // and writing respectively.
 | 
				
			||||||
  FMT_API static void pipe(file &read_end, file &write_end);
 | 
					  FMT_API static void pipe(file& read_end, file& write_end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Creates a buffered_file object associated with this file and detaches
 | 
					  // Creates a buffered_file object associated with this file and detaches
 | 
				
			||||||
  // this file object from the file.
 | 
					  // this file object from the file.
 | 
				
			||||||
  FMT_API buffered_file fdopen(const char *mode);
 | 
					  FMT_API buffered_file fdopen(const char* mode);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Returns the memory page size.
 | 
					// Returns the memory page size.
 | 
				
			||||||
long getpagesize();
 | 
					long getpagesize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
 | 
					 | 
				
			||||||
    !defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__) && \
 | 
					 | 
				
			||||||
    !defined(__NEWLIB_H__)
 | 
					 | 
				
			||||||
# define FMT_LOCALE
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef FMT_LOCALE
 | 
					#ifdef FMT_LOCALE
 | 
				
			||||||
// A "C" numeric locale.
 | 
					// A "C" numeric locale.
 | 
				
			||||||
class Locale {
 | 
					class Locale {
 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
# ifdef _MSC_VER
 | 
					#  ifdef _WIN32
 | 
				
			||||||
  typedef _locale_t locale_t;
 | 
					  using locale_t = _locale_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  enum { LC_NUMERIC_MASK = LC_NUMERIC };
 | 
					  enum { LC_NUMERIC_MASK = LC_NUMERIC };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static locale_t newlocale(int category_mask, const char *locale, locale_t) {
 | 
					  static locale_t newlocale(int category_mask, const char* locale, locale_t) {
 | 
				
			||||||
    return _create_locale(category_mask, locale);
 | 
					    return _create_locale(category_mask, locale);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static void freelocale(locale_t locale) {
 | 
					  static void freelocale(locale_t locale) { _free_locale(locale); }
 | 
				
			||||||
    _free_locale(locale);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static double strtod_l(const char *nptr, char **endptr, _locale_t locale) {
 | 
					  static double strtod_l(const char* nptr, char** endptr, _locale_t locale) {
 | 
				
			||||||
    return _strtod_l(nptr, endptr, locale);
 | 
					    return _strtod_l(nptr, endptr, locale);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#  endif
 | 
					#  endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  locale_t locale_;
 | 
					  locale_t locale_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Locale(const Locale &) = delete;
 | 
					  Locale(const Locale&) = delete;
 | 
				
			||||||
  void operator=(const Locale &) = delete;
 | 
					  void operator=(const Locale&) = delete;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  typedef locale_t Type;
 | 
					  using type = locale_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) {
 | 
					  Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", nullptr)) {
 | 
				
			||||||
    if (!locale_)
 | 
					    if (!locale_) FMT_THROW(system_error(errno, "cannot create locale"));
 | 
				
			||||||
      FMT_THROW(system_error(errno, "cannot create locale"));
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  ~Locale() { freelocale(locale_); }
 | 
					  ~Locale() { freelocale(locale_); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Type get() const { return locale_; }
 | 
					  type get() const { return locale_; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Converts string to floating-point number and advances str past the end
 | 
					  // Converts string to floating-point number and advances str past the end
 | 
				
			||||||
  // of the parsed input.
 | 
					  // of the parsed input.
 | 
				
			||||||
  double strtod(const char *&str) const {
 | 
					  double strtod(const char*& str) const {
 | 
				
			||||||
    char *end = FMT_NULL;
 | 
					    char* end = nullptr;
 | 
				
			||||||
    double result = strtod_l(str, &end, locale_);
 | 
					    double result = strtod_l(str, &end, locale_);
 | 
				
			||||||
    str = end;
 | 
					    str = end;
 | 
				
			||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -1,4 +1,4 @@
 | 
				
			|||||||
// Formatting library for C++ - the core API
 | 
					// Formatting library for C++ - experimental range support
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
// Copyright (c) 2012 - present, Victor Zverovich
 | 
					// Copyright (c) 2012 - present, Victor Zverovich
 | 
				
			||||||
// All rights reserved.
 | 
					// All rights reserved.
 | 
				
			||||||
@ -12,8 +12,8 @@
 | 
				
			|||||||
#ifndef FMT_RANGES_H_
 | 
					#ifndef FMT_RANGES_H_
 | 
				
			||||||
#define FMT_RANGES_H_
 | 
					#define FMT_RANGES_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "format.h"
 | 
					 | 
				
			||||||
#include <type_traits>
 | 
					#include <type_traits>
 | 
				
			||||||
 | 
					#include "format.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// output only up to N items from the range.
 | 
					// output only up to N items from the range.
 | 
				
			||||||
#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT
 | 
					#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT
 | 
				
			||||||
@ -22,10 +22,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
FMT_BEGIN_NAMESPACE
 | 
					FMT_BEGIN_NAMESPACE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename Char>
 | 
					template <typename Char> struct formatting_base {
 | 
				
			||||||
struct formatting_base {
 | 
					 | 
				
			||||||
  template <typename ParseContext>
 | 
					  template <typename ParseContext>
 | 
				
			||||||
  FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
 | 
					  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
 | 
				
			||||||
    return ctx.begin();
 | 
					    return ctx.begin();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -33,7 +32,8 @@ struct formatting_base {
 | 
				
			|||||||
template <typename Char, typename Enable = void>
 | 
					template <typename Char, typename Enable = void>
 | 
				
			||||||
struct formatting_range : formatting_base<Char> {
 | 
					struct formatting_range : formatting_base<Char> {
 | 
				
			||||||
  static FMT_CONSTEXPR_DECL const std::size_t range_length_limit =
 | 
					  static FMT_CONSTEXPR_DECL const std::size_t range_length_limit =
 | 
				
			||||||
      FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range.
 | 
					      FMT_RANGE_OUTPUT_LENGTH_LIMIT;  // output only up to N items from the
 | 
				
			||||||
 | 
					                                      // range.
 | 
				
			||||||
  Char prefix;
 | 
					  Char prefix;
 | 
				
			||||||
  Char delimiter;
 | 
					  Char delimiter;
 | 
				
			||||||
  Char postfix;
 | 
					  Char postfix;
 | 
				
			||||||
@ -55,87 +55,78 @@ struct formatting_tuple : formatting_base<Char> {
 | 
				
			|||||||
namespace internal {
 | 
					namespace internal {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename RangeT, typename OutputIterator>
 | 
					template <typename RangeT, typename OutputIterator>
 | 
				
			||||||
void copy(const RangeT &range, OutputIterator out) {
 | 
					OutputIterator copy(const RangeT& range, OutputIterator out) {
 | 
				
			||||||
  for (auto it = range.begin(), end = range.end(); it != end; ++it)
 | 
					  for (auto it = range.begin(), end = range.end(); it != end; ++it)
 | 
				
			||||||
    *out++ = *it;
 | 
					    *out++ = *it;
 | 
				
			||||||
 | 
					  return out;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename OutputIterator>
 | 
					template <typename OutputIterator>
 | 
				
			||||||
void copy(const char *str, OutputIterator out) {
 | 
					OutputIterator copy(const char* str, OutputIterator out) {
 | 
				
			||||||
  const char *p_curr = str;
 | 
					  while (*str) *out++ = *str++;
 | 
				
			||||||
  while (*p_curr) {
 | 
					  return out;
 | 
				
			||||||
    *out++ = *p_curr++;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename OutputIterator>
 | 
					template <typename OutputIterator>
 | 
				
			||||||
void copy(char ch, OutputIterator out) {
 | 
					OutputIterator copy(char ch, OutputIterator out) {
 | 
				
			||||||
  *out++ = ch;
 | 
					  *out++ = ch;
 | 
				
			||||||
 | 
					  return out;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Return true value if T has std::string interface, like std::string_view.
 | 
					/// Return true value if T has std::string interface, like std::string_view.
 | 
				
			||||||
template <typename T>
 | 
					template <typename T> class is_like_std_string {
 | 
				
			||||||
class is_like_std_string {
 | 
					 | 
				
			||||||
  template <typename U>
 | 
					  template <typename U>
 | 
				
			||||||
  static auto check(U *p) ->
 | 
					  static auto check(U* p)
 | 
				
			||||||
    decltype(p->find('a'), p->length(), p->data(), int());
 | 
					      -> decltype((void)p->find('a'), p->length(), (void)p->data(), int());
 | 
				
			||||||
  template <typename>
 | 
					  template <typename> static void check(...);
 | 
				
			||||||
  static void check(...);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  static FMT_CONSTEXPR_DECL const bool value =
 | 
					  static FMT_CONSTEXPR_DECL const bool value =
 | 
				
			||||||
    !std::is_void<decltype(check<T>(FMT_NULL))>::value;
 | 
					      is_string<T>::value || !std::is_void<decltype(check<T>(nullptr))>::value;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename Char>
 | 
					template <typename Char>
 | 
				
			||||||
struct is_like_std_string<fmt::basic_string_view<Char>> : std::true_type {};
 | 
					struct is_like_std_string<fmt::basic_string_view<Char>> : std::true_type {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename... Ts>
 | 
					template <typename... Ts> struct conditional_helper {};
 | 
				
			||||||
struct conditional_helper {};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename T, typename _ = void>
 | 
					template <typename T, typename _ = void> struct is_range_ : std::false_type {};
 | 
				
			||||||
struct is_range_ : std::false_type {};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
 | 
					#if !FMT_MSC_VER || FMT_MSC_VER > 1800
 | 
				
			||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
struct is_range_<T, typename std::conditional<
 | 
					struct is_range_<
 | 
				
			||||||
                    false,
 | 
					    T, conditional_t<false,
 | 
				
			||||||
                    conditional_helper<decltype(internal::declval<T>().begin()),
 | 
					                     conditional_helper<decltype(std::declval<T>().begin()),
 | 
				
			||||||
                                       decltype(internal::declval<T>().end())>,
 | 
					                                        decltype(std::declval<T>().end())>,
 | 
				
			||||||
                    void>::type> : std::true_type {};
 | 
					                     void>> : std::true_type {};
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// tuple_size and tuple_element check.
 | 
					/// tuple_size and tuple_element check.
 | 
				
			||||||
template <typename T>
 | 
					template <typename T> class is_tuple_like_ {
 | 
				
			||||||
class is_tuple_like_ {
 | 
					 | 
				
			||||||
  template <typename U>
 | 
					  template <typename U>
 | 
				
			||||||
  static auto check(U *p) ->
 | 
					  static auto check(U* p)
 | 
				
			||||||
    decltype(std::tuple_size<U>::value,
 | 
					      -> decltype(std::tuple_size<U>::value,
 | 
				
			||||||
      internal::declval<typename std::tuple_element<0, U>::type>(), int());
 | 
					                  (void)std::declval<typename std::tuple_element<0, U>::type>(),
 | 
				
			||||||
  template <typename>
 | 
					                  int());
 | 
				
			||||||
  static void check(...);
 | 
					  template <typename> static void check(...);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  static FMT_CONSTEXPR_DECL const bool value =
 | 
					  static FMT_CONSTEXPR_DECL const bool value =
 | 
				
			||||||
    !std::is_void<decltype(check<T>(FMT_NULL))>::value;
 | 
					      !std::is_void<decltype(check<T>(nullptr))>::value;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Check for integer_sequence
 | 
					// Check for integer_sequence
 | 
				
			||||||
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
 | 
					#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
 | 
				
			||||||
template <typename T, T... N>
 | 
					template <typename T, T... N>
 | 
				
			||||||
using integer_sequence = std::integer_sequence<T, N...>;
 | 
					using integer_sequence = std::integer_sequence<T, N...>;
 | 
				
			||||||
template <std::size_t... N>
 | 
					template <std::size_t... N> using index_sequence = std::index_sequence<N...>;
 | 
				
			||||||
using index_sequence = std::index_sequence<N...>;
 | 
					 | 
				
			||||||
template <std::size_t N>
 | 
					template <std::size_t N>
 | 
				
			||||||
using make_index_sequence = std::make_index_sequence<N>;
 | 
					using make_index_sequence = std::make_index_sequence<N>;
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
template <typename T, T... N>
 | 
					template <typename T, T... N> struct integer_sequence {
 | 
				
			||||||
struct integer_sequence {
 | 
					  using value_type = T;
 | 
				
			||||||
  typedef T value_type;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static FMT_CONSTEXPR std::size_t size() {
 | 
					  static FMT_CONSTEXPR std::size_t size() { return sizeof...(N); }
 | 
				
			||||||
    return sizeof...(N);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <std::size_t... N>
 | 
					template <std::size_t... N>
 | 
				
			||||||
@ -151,7 +142,7 @@ using make_index_sequence = make_integer_sequence<std::size_t, N>;
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <class Tuple, class F, size_t... Is>
 | 
					template <class Tuple, class F, size_t... Is>
 | 
				
			||||||
void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) FMT_NOEXCEPT {
 | 
					void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) FMT_NOEXCEPT {
 | 
				
			||||||
  using std::get;
 | 
					  using std::get;
 | 
				
			||||||
  // using free function get<I>(T) now.
 | 
					  // using free function get<I>(T) now.
 | 
				
			||||||
  const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
 | 
					  const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
 | 
				
			||||||
@ -159,26 +150,25 @@ void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) FMT_NOEXCEPT {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <class T>
 | 
					template <class T>
 | 
				
			||||||
FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> 
 | 
					FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes(
 | 
				
			||||||
get_indexes(T const &) { return {}; }
 | 
					    T const&) {
 | 
				
			||||||
 | 
					  return {};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <class Tuple, class F>
 | 
					template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
 | 
				
			||||||
void for_each(Tuple &&tup, F &&f) {
 | 
					 | 
				
			||||||
  const auto indexes = get_indexes(tup);
 | 
					  const auto indexes = get_indexes(tup);
 | 
				
			||||||
  for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
 | 
					  for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename Arg>
 | 
					template <typename Arg, FMT_ENABLE_IF(!is_like_std_string<
 | 
				
			||||||
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&, 
 | 
					                                      typename std::decay<Arg>::type>::value)>
 | 
				
			||||||
  typename std::enable_if<
 | 
					FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) {
 | 
				
			||||||
    !is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
 | 
					 | 
				
			||||||
  return add_space ? " {}" : "{}";
 | 
					  return add_space ? " {}" : "{}";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename Arg>
 | 
					template <typename Arg, FMT_ENABLE_IF(is_like_std_string<
 | 
				
			||||||
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&, 
 | 
					                                      typename std::decay<Arg>::type>::value)>
 | 
				
			||||||
  typename std::enable_if<
 | 
					FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) {
 | 
				
			||||||
    is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
 | 
					 | 
				
			||||||
  return add_space ? " \"{}\"" : "\"{}\"";
 | 
					  return add_space ? " \"{}\"" : "\"{}\"";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -198,28 +188,24 @@ FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}  // namespace internal
 | 
					}  // namespace internal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename T>
 | 
					template <typename T> struct is_tuple_like {
 | 
				
			||||||
struct is_tuple_like {
 | 
					 | 
				
			||||||
  static FMT_CONSTEXPR_DECL const bool value =
 | 
					  static FMT_CONSTEXPR_DECL const bool value =
 | 
				
			||||||
      internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value;
 | 
					      internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename TupleT, typename Char>
 | 
					template <typename TupleT, typename Char>
 | 
				
			||||||
struct formatter<TupleT, Char, 
 | 
					struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
 | 
				
			||||||
    typename std::enable_if<fmt::is_tuple_like<TupleT>::value>::type> {
 | 
					 private:
 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
  // C++11 generic lambda for format()
 | 
					  // C++11 generic lambda for format()
 | 
				
			||||||
  template <typename FormatContext>
 | 
					  template <typename FormatContext> struct format_each {
 | 
				
			||||||
  struct format_each {
 | 
					    template <typename T> void operator()(const T& v) {
 | 
				
			||||||
    template <typename T>
 | 
					 | 
				
			||||||
    void operator()(const T& v) {
 | 
					 | 
				
			||||||
      if (i > 0) {
 | 
					      if (i > 0) {
 | 
				
			||||||
        if (formatting.add_prepostfix_space) {
 | 
					        if (formatting.add_prepostfix_space) {
 | 
				
			||||||
          *out++ = ' ';
 | 
					          *out++ = ' ';
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        internal::copy(formatting.delimiter, out);
 | 
					        out = internal::copy(formatting.delimiter, out);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      format_to(out,
 | 
					      out = format_to(out,
 | 
				
			||||||
                      internal::format_str_quoted(
 | 
					                      internal::format_str_quoted(
 | 
				
			||||||
                          (formatting.add_delimiter_spaces && i > 0), v),
 | 
					                          (formatting.add_delimiter_spaces && i > 0), v),
 | 
				
			||||||
                      v);
 | 
					                      v);
 | 
				
			||||||
@ -228,19 +214,20 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    formatting_tuple<Char>& formatting;
 | 
					    formatting_tuple<Char>& formatting;
 | 
				
			||||||
    std::size_t& i;
 | 
					    std::size_t& i;
 | 
				
			||||||
    typename std::add_lvalue_reference<decltype(std::declval<FormatContext>().out())>::type out;
 | 
					    typename std::add_lvalue_reference<decltype(
 | 
				
			||||||
 | 
					        std::declval<FormatContext>().out())>::type out;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					 public:
 | 
				
			||||||
  formatting_tuple<Char> formatting;
 | 
					  formatting_tuple<Char> formatting;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template <typename ParseContext>
 | 
					  template <typename ParseContext>
 | 
				
			||||||
  FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
 | 
					  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
 | 
				
			||||||
    return formatting.parse(ctx);
 | 
					    return formatting.parse(ctx);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template <typename FormatContext = format_context>
 | 
					  template <typename FormatContext = format_context>
 | 
				
			||||||
  auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) {
 | 
					  auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) {
 | 
				
			||||||
    auto out = ctx.out();
 | 
					    auto out = ctx.out();
 | 
				
			||||||
    std::size_t i = 0;
 | 
					    std::size_t i = 0;
 | 
				
			||||||
    internal::copy(formatting.prefix, out);
 | 
					    internal::copy(formatting.prefix, out);
 | 
				
			||||||
@ -255,54 +242,47 @@ public:
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename T>
 | 
					template <typename T, typename Char> struct is_range {
 | 
				
			||||||
struct is_range {
 | 
					 | 
				
			||||||
  static FMT_CONSTEXPR_DECL const bool value =
 | 
					  static FMT_CONSTEXPR_DECL const bool value =
 | 
				
			||||||
    internal::is_range_<T>::value && !internal::is_like_std_string<T>::value;
 | 
					      internal::is_range_<T>::value &&
 | 
				
			||||||
 | 
					      !internal::is_like_std_string<T>::value &&
 | 
				
			||||||
 | 
					      !std::is_convertible<T, std::basic_string<Char>>::value;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template <typename RangeT, typename Char>
 | 
					template <typename RangeT, typename Char>
 | 
				
			||||||
struct formatter<RangeT, Char,
 | 
					struct formatter<RangeT, Char,
 | 
				
			||||||
    typename std::enable_if<fmt::is_range<RangeT>::value>::type> {
 | 
					                 enable_if_t<fmt::is_range<RangeT, Char>::value>> {
 | 
				
			||||||
 | 
					 | 
				
			||||||
  formatting_range<Char> formatting;
 | 
					  formatting_range<Char> formatting;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template <typename ParseContext>
 | 
					  template <typename ParseContext>
 | 
				
			||||||
  FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
 | 
					  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
 | 
				
			||||||
    return formatting.parse(ctx);
 | 
					    return formatting.parse(ctx);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template <typename FormatContext>
 | 
					  template <typename FormatContext>
 | 
				
			||||||
  typename FormatContext::iterator format(
 | 
					  typename FormatContext::iterator format(const RangeT& values,
 | 
				
			||||||
      const RangeT &values, FormatContext &ctx) {
 | 
					                                          FormatContext& ctx) {
 | 
				
			||||||
    auto out = ctx.out();
 | 
					    auto out = internal::copy(formatting.prefix, ctx.out());
 | 
				
			||||||
    internal::copy(formatting.prefix, out);
 | 
					 | 
				
			||||||
    std::size_t i = 0;
 | 
					    std::size_t i = 0;
 | 
				
			||||||
    for (auto it = values.begin(), end = values.end(); it != end; ++it) {
 | 
					    for (auto it = values.begin(), end = values.end(); it != end; ++it) {
 | 
				
			||||||
      if (i > 0) {
 | 
					      if (i > 0) {
 | 
				
			||||||
        if (formatting.add_prepostfix_space) {
 | 
					        if (formatting.add_prepostfix_space) *out++ = ' ';
 | 
				
			||||||
          *out++ = ' ';
 | 
					        out = internal::copy(formatting.delimiter, out);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
        internal::copy(formatting.delimiter, out);
 | 
					      out = format_to(out,
 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      format_to(out,
 | 
					 | 
				
			||||||
                      internal::format_str_quoted(
 | 
					                      internal::format_str_quoted(
 | 
				
			||||||
                          (formatting.add_delimiter_spaces && i > 0), *it),
 | 
					                          (formatting.add_delimiter_spaces && i > 0), *it),
 | 
				
			||||||
                      *it);
 | 
					                      *it);
 | 
				
			||||||
      if (++i > formatting.range_length_limit) {
 | 
					      if (++i > formatting.range_length_limit) {
 | 
				
			||||||
        format_to(out, " ... <other elements>");
 | 
					        out = format_to(out, " ... <other elements>");
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (formatting.add_prepostfix_space) {
 | 
					    if (formatting.add_prepostfix_space) *out++ = ' ';
 | 
				
			||||||
      *out++ = ' ';
 | 
					    return internal::copy(formatting.postfix, out);
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    internal::copy(formatting.postfix, out);
 | 
					 | 
				
			||||||
    return ctx.out();
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FMT_END_NAMESPACE
 | 
					FMT_END_NAMESPACE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif  // FMT_RANGES_H_
 | 
					#endif  // FMT_RANGES_H_
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										293
									
								
								include/spdlog/fmt/bundled/safe-duration-cast.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										293
									
								
								include/spdlog/fmt/bundled/safe-duration-cast.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,293 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * For conversion between std::chrono::durations without undefined
 | 
				
			||||||
 | 
					 * behaviour or erroneous results.
 | 
				
			||||||
 | 
					 * This is a stripped down version of duration_cast, for inclusion in fmt.
 | 
				
			||||||
 | 
					 * See https://github.com/pauldreik/safe_duration_cast
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright Paul Dreik 2019
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This file is licensed under the fmt license, see format.h
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <chrono>
 | 
				
			||||||
 | 
					#include <cmath>
 | 
				
			||||||
 | 
					#include <limits>
 | 
				
			||||||
 | 
					#include <type_traits>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "format.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FMT_BEGIN_NAMESPACE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace safe_duration_cast {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename To, typename From,
 | 
				
			||||||
 | 
					          FMT_ENABLE_IF(!std::is_same<From, To>::value &&
 | 
				
			||||||
 | 
					                        std::numeric_limits<From>::is_signed ==
 | 
				
			||||||
 | 
					                            std::numeric_limits<To>::is_signed)>
 | 
				
			||||||
 | 
					FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
 | 
				
			||||||
 | 
					  ec = 0;
 | 
				
			||||||
 | 
					  using F = std::numeric_limits<From>;
 | 
				
			||||||
 | 
					  using T = std::numeric_limits<To>;
 | 
				
			||||||
 | 
					  static_assert(F::is_integer, "From must be integral");
 | 
				
			||||||
 | 
					  static_assert(T::is_integer, "To must be integral");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // A and B are both signed, or both unsigned.
 | 
				
			||||||
 | 
					  if (F::digits <= T::digits) {
 | 
				
			||||||
 | 
					    // From fits in To without any problem.
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    // From does not always fit in To, resort to a dynamic check.
 | 
				
			||||||
 | 
					    if (from < T::min() || from > T::max()) {
 | 
				
			||||||
 | 
					      // outside range.
 | 
				
			||||||
 | 
					      ec = 1;
 | 
				
			||||||
 | 
					      return {};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return static_cast<To>(from);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * converts From to To, without loss. If the dynamic value of from
 | 
				
			||||||
 | 
					 * can't be converted to To without loss, ec is set.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					template <typename To, typename From,
 | 
				
			||||||
 | 
					          FMT_ENABLE_IF(!std::is_same<From, To>::value &&
 | 
				
			||||||
 | 
					                        std::numeric_limits<From>::is_signed !=
 | 
				
			||||||
 | 
					                            std::numeric_limits<To>::is_signed)>
 | 
				
			||||||
 | 
					FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
 | 
				
			||||||
 | 
					  ec = 0;
 | 
				
			||||||
 | 
					  using F = std::numeric_limits<From>;
 | 
				
			||||||
 | 
					  using T = std::numeric_limits<To>;
 | 
				
			||||||
 | 
					  static_assert(F::is_integer, "From must be integral");
 | 
				
			||||||
 | 
					  static_assert(T::is_integer, "To must be integral");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (F::is_signed && !T::is_signed) {
 | 
				
			||||||
 | 
					    // From may be negative, not allowed!
 | 
				
			||||||
 | 
					    if (from < 0) {
 | 
				
			||||||
 | 
					      ec = 1;
 | 
				
			||||||
 | 
					      return {};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // From is positive. Can it always fit in To?
 | 
				
			||||||
 | 
					    if (F::digits <= T::digits) {
 | 
				
			||||||
 | 
					      // yes, From always fits in To.
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      // from may not fit in To, we have to do a dynamic check
 | 
				
			||||||
 | 
					      if (from > static_cast<From>(T::max())) {
 | 
				
			||||||
 | 
					        ec = 1;
 | 
				
			||||||
 | 
					        return {};
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!F::is_signed && T::is_signed) {
 | 
				
			||||||
 | 
					    // can from be held in To?
 | 
				
			||||||
 | 
					    if (F::digits < T::digits) {
 | 
				
			||||||
 | 
					      // yes, From always fits in To.
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      // from may not fit in To, we have to do a dynamic check
 | 
				
			||||||
 | 
					      if (from > static_cast<From>(T::max())) {
 | 
				
			||||||
 | 
					        // outside range.
 | 
				
			||||||
 | 
					        ec = 1;
 | 
				
			||||||
 | 
					        return {};
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // reaching here means all is ok for lossless conversion.
 | 
				
			||||||
 | 
					  return static_cast<To>(from);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename To, typename From,
 | 
				
			||||||
 | 
					          FMT_ENABLE_IF(std::is_same<From, To>::value)>
 | 
				
			||||||
 | 
					FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
 | 
				
			||||||
 | 
					  ec = 0;
 | 
				
			||||||
 | 
					  return from;
 | 
				
			||||||
 | 
					}  // function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// clang-format off
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * converts From to To if possible, otherwise ec is set.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * input                            |    output
 | 
				
			||||||
 | 
					 * ---------------------------------|---------------
 | 
				
			||||||
 | 
					 * NaN                              | NaN
 | 
				
			||||||
 | 
					 * Inf                              | Inf
 | 
				
			||||||
 | 
					 * normal, fits in output           | converted (possibly lossy)
 | 
				
			||||||
 | 
					 * normal, does not fit in output   | ec is set
 | 
				
			||||||
 | 
					 * subnormal                        | best effort
 | 
				
			||||||
 | 
					 * -Inf                             | -Inf
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					// clang-format on
 | 
				
			||||||
 | 
					template <typename To, typename From,
 | 
				
			||||||
 | 
					          FMT_ENABLE_IF(!std::is_same<From, To>::value)>
 | 
				
			||||||
 | 
					FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
 | 
				
			||||||
 | 
					  ec = 0;
 | 
				
			||||||
 | 
					  using T = std::numeric_limits<To>;
 | 
				
			||||||
 | 
					  static_assert(std::is_floating_point<From>::value, "From must be floating");
 | 
				
			||||||
 | 
					  static_assert(std::is_floating_point<To>::value, "To must be floating");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // catch the only happy case
 | 
				
			||||||
 | 
					  if (std::isfinite(from)) {
 | 
				
			||||||
 | 
					    if (from >= T::lowest() && from <= T::max()) {
 | 
				
			||||||
 | 
					      return static_cast<To>(from);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // not within range.
 | 
				
			||||||
 | 
					    ec = 1;
 | 
				
			||||||
 | 
					    return {};
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // nan and inf will be preserved
 | 
				
			||||||
 | 
					  return static_cast<To>(from);
 | 
				
			||||||
 | 
					}  // function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template <typename To, typename From,
 | 
				
			||||||
 | 
					          FMT_ENABLE_IF(std::is_same<From, To>::value)>
 | 
				
			||||||
 | 
					FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
 | 
				
			||||||
 | 
					  ec = 0;
 | 
				
			||||||
 | 
					  static_assert(std::is_floating_point<From>::value, "From must be floating");
 | 
				
			||||||
 | 
					  return from;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * safe duration cast between integral durations
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					template <typename To, typename FromRep, typename FromPeriod,
 | 
				
			||||||
 | 
					          FMT_ENABLE_IF(std::is_integral<FromRep>::value),
 | 
				
			||||||
 | 
					          FMT_ENABLE_IF(std::is_integral<typename To::rep>::value)>
 | 
				
			||||||
 | 
					To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
 | 
				
			||||||
 | 
					                      int& ec) {
 | 
				
			||||||
 | 
					  using From = std::chrono::duration<FromRep, FromPeriod>;
 | 
				
			||||||
 | 
					  ec = 0;
 | 
				
			||||||
 | 
					  // the basic idea is that we need to convert from count() in the from type
 | 
				
			||||||
 | 
					  // to count() in the To type, by multiplying it with this:
 | 
				
			||||||
 | 
					  using Factor = std::ratio_divide<typename From::period, typename To::period>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static_assert(Factor::num > 0, "num must be positive");
 | 
				
			||||||
 | 
					  static_assert(Factor::den > 0, "den must be positive");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // the conversion is like this: multiply from.count() with Factor::num
 | 
				
			||||||
 | 
					  // /Factor::den and convert it to To::rep, all this without
 | 
				
			||||||
 | 
					  // overflow/underflow. let's start by finding a suitable type that can hold
 | 
				
			||||||
 | 
					  // both To, From and Factor::num
 | 
				
			||||||
 | 
					  using IntermediateRep =
 | 
				
			||||||
 | 
					      typename std::common_type<typename From::rep, typename To::rep,
 | 
				
			||||||
 | 
					                                decltype(Factor::num)>::type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // safe conversion to IntermediateRep
 | 
				
			||||||
 | 
					  IntermediateRep count =
 | 
				
			||||||
 | 
					      lossless_integral_conversion<IntermediateRep>(from.count(), ec);
 | 
				
			||||||
 | 
					  if (ec) {
 | 
				
			||||||
 | 
					    return {};
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // multiply with Factor::num without overflow or underflow
 | 
				
			||||||
 | 
					  if (Factor::num != 1) {
 | 
				
			||||||
 | 
					    constexpr auto max1 =
 | 
				
			||||||
 | 
					        std::numeric_limits<IntermediateRep>::max() / Factor::num;
 | 
				
			||||||
 | 
					    if (count > max1) {
 | 
				
			||||||
 | 
					      ec = 1;
 | 
				
			||||||
 | 
					      return {};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    constexpr auto min1 =
 | 
				
			||||||
 | 
					        std::numeric_limits<IntermediateRep>::min() / Factor::num;
 | 
				
			||||||
 | 
					    if (count < min1) {
 | 
				
			||||||
 | 
					      ec = 1;
 | 
				
			||||||
 | 
					      return {};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    count *= Factor::num;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // this can't go wrong, right? den>0 is checked earlier.
 | 
				
			||||||
 | 
					  if (Factor::den != 1) {
 | 
				
			||||||
 | 
					    count /= Factor::den;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // convert to the to type, safely
 | 
				
			||||||
 | 
					  using ToRep = typename To::rep;
 | 
				
			||||||
 | 
					  const ToRep tocount = lossless_integral_conversion<ToRep>(count, ec);
 | 
				
			||||||
 | 
					  if (ec) {
 | 
				
			||||||
 | 
					    return {};
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return To{tocount};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * safe duration_cast between floating point durations
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					template <typename To, typename FromRep, typename FromPeriod,
 | 
				
			||||||
 | 
					          FMT_ENABLE_IF(std::is_floating_point<FromRep>::value),
 | 
				
			||||||
 | 
					          FMT_ENABLE_IF(std::is_floating_point<typename To::rep>::value)>
 | 
				
			||||||
 | 
					To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
 | 
				
			||||||
 | 
					                      int& ec) {
 | 
				
			||||||
 | 
					  using From = std::chrono::duration<FromRep, FromPeriod>;
 | 
				
			||||||
 | 
					  ec = 0;
 | 
				
			||||||
 | 
					  if (std::isnan(from.count())) {
 | 
				
			||||||
 | 
					    // nan in, gives nan out. easy.
 | 
				
			||||||
 | 
					    return To{std::numeric_limits<typename To::rep>::quiet_NaN()};
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  // maybe we should also check if from is denormal, and decide what to do about
 | 
				
			||||||
 | 
					  // it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // +-inf should be preserved.
 | 
				
			||||||
 | 
					  if (std::isinf(from.count())) {
 | 
				
			||||||
 | 
					    return To{from.count()};
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // the basic idea is that we need to convert from count() in the from type
 | 
				
			||||||
 | 
					  // to count() in the To type, by multiplying it with this:
 | 
				
			||||||
 | 
					  using Factor = std::ratio_divide<typename From::period, typename To::period>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static_assert(Factor::num > 0, "num must be positive");
 | 
				
			||||||
 | 
					  static_assert(Factor::den > 0, "den must be positive");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // the conversion is like this: multiply from.count() with Factor::num
 | 
				
			||||||
 | 
					  // /Factor::den and convert it to To::rep, all this without
 | 
				
			||||||
 | 
					  // overflow/underflow. let's start by finding a suitable type that can hold
 | 
				
			||||||
 | 
					  // both To, From and Factor::num
 | 
				
			||||||
 | 
					  using IntermediateRep =
 | 
				
			||||||
 | 
					      typename std::common_type<typename From::rep, typename To::rep,
 | 
				
			||||||
 | 
					                                decltype(Factor::num)>::type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // force conversion of From::rep -> IntermediateRep to be safe,
 | 
				
			||||||
 | 
					  // even if it will never happen be narrowing in this context.
 | 
				
			||||||
 | 
					  IntermediateRep count =
 | 
				
			||||||
 | 
					      safe_float_conversion<IntermediateRep>(from.count(), ec);
 | 
				
			||||||
 | 
					  if (ec) {
 | 
				
			||||||
 | 
					    return {};
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // multiply with Factor::num without overflow or underflow
 | 
				
			||||||
 | 
					  if (Factor::num != 1) {
 | 
				
			||||||
 | 
					    constexpr auto max1 = std::numeric_limits<IntermediateRep>::max() /
 | 
				
			||||||
 | 
					                          static_cast<IntermediateRep>(Factor::num);
 | 
				
			||||||
 | 
					    if (count > max1) {
 | 
				
			||||||
 | 
					      ec = 1;
 | 
				
			||||||
 | 
					      return {};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    constexpr auto min1 = std::numeric_limits<IntermediateRep>::lowest() /
 | 
				
			||||||
 | 
					                          static_cast<IntermediateRep>(Factor::num);
 | 
				
			||||||
 | 
					    if (count < min1) {
 | 
				
			||||||
 | 
					      ec = 1;
 | 
				
			||||||
 | 
					      return {};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    count *= static_cast<IntermediateRep>(Factor::num);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // this can't go wrong, right? den>0 is checked earlier.
 | 
				
			||||||
 | 
					  if (Factor::den != 1) {
 | 
				
			||||||
 | 
					    using common_t = typename std::common_type<IntermediateRep, intmax_t>::type;
 | 
				
			||||||
 | 
					    count /= static_cast<common_t>(Factor::den);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // convert to the to type, safely
 | 
				
			||||||
 | 
					  using ToRep = typename To::rep;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const ToRep tocount = safe_float_conversion<ToRep>(count, ec);
 | 
				
			||||||
 | 
					  if (ec) {
 | 
				
			||||||
 | 
					    return {};
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return To{tocount};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace safe_duration_cast
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FMT_END_NAMESPACE
 | 
				
			||||||
@ -1,160 +0,0 @@
 | 
				
			|||||||
// Formatting library for C++ - time formatting
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Copyright (c) 2012 - present, Victor Zverovich
 | 
					 | 
				
			||||||
// All rights reserved.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// For the license information refer to format.h.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef FMT_TIME_H_
 | 
					 | 
				
			||||||
#define FMT_TIME_H_
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "format.h"
 | 
					 | 
				
			||||||
#include <ctime>
 | 
					 | 
				
			||||||
#include <locale>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FMT_BEGIN_NAMESPACE
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Prevents expansion of a preceding token as a function-style macro.
 | 
					 | 
				
			||||||
// Usage: f FMT_NOMACRO()
 | 
					 | 
				
			||||||
#define FMT_NOMACRO
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace internal{
 | 
					 | 
				
			||||||
inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
 | 
					 | 
				
			||||||
inline null<> localtime_s(...) { return null<>(); }
 | 
					 | 
				
			||||||
inline null<> gmtime_r(...) { return null<>(); }
 | 
					 | 
				
			||||||
inline null<> gmtime_s(...) { return null<>(); }
 | 
					 | 
				
			||||||
}  // namespace internal
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Thread-safe replacement for std::localtime
 | 
					 | 
				
			||||||
inline std::tm localtime(std::time_t time) {
 | 
					 | 
				
			||||||
  struct dispatcher {
 | 
					 | 
				
			||||||
    std::time_t time_;
 | 
					 | 
				
			||||||
    std::tm tm_;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dispatcher(std::time_t t): time_(t) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool run() {
 | 
					 | 
				
			||||||
      using namespace fmt::internal;
 | 
					 | 
				
			||||||
      return handle(localtime_r(&time_, &tm_));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool handle(std::tm *tm) { return tm != FMT_NULL; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool handle(internal::null<>) {
 | 
					 | 
				
			||||||
      using namespace fmt::internal;
 | 
					 | 
				
			||||||
      return fallback(localtime_s(&tm_, &time_));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool fallback(int res) { return res == 0; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if !FMT_MSC_VER
 | 
					 | 
				
			||||||
    bool fallback(internal::null<>) {
 | 
					 | 
				
			||||||
      using namespace fmt::internal;
 | 
					 | 
				
			||||||
      std::tm *tm = std::localtime(&time_);
 | 
					 | 
				
			||||||
      if (tm) tm_ = *tm;
 | 
					 | 
				
			||||||
      return tm != FMT_NULL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  dispatcher lt(time);
 | 
					 | 
				
			||||||
  // Too big time values may be unsupported.
 | 
					 | 
				
			||||||
  if (!lt.run())
 | 
					 | 
				
			||||||
    FMT_THROW(format_error("time_t value out of range"));
 | 
					 | 
				
			||||||
  return lt.tm_;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Thread-safe replacement for std::gmtime
 | 
					 | 
				
			||||||
inline std::tm gmtime(std::time_t time) {
 | 
					 | 
				
			||||||
  struct dispatcher {
 | 
					 | 
				
			||||||
    std::time_t time_;
 | 
					 | 
				
			||||||
    std::tm tm_;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dispatcher(std::time_t t): time_(t) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool run() {
 | 
					 | 
				
			||||||
      using namespace fmt::internal;
 | 
					 | 
				
			||||||
      return handle(gmtime_r(&time_, &tm_));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool handle(std::tm *tm) { return tm != FMT_NULL; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool handle(internal::null<>) {
 | 
					 | 
				
			||||||
      using namespace fmt::internal;
 | 
					 | 
				
			||||||
      return fallback(gmtime_s(&tm_, &time_));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool fallback(int res) { return res == 0; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if !FMT_MSC_VER
 | 
					 | 
				
			||||||
    bool fallback(internal::null<>) {
 | 
					 | 
				
			||||||
      std::tm *tm = std::gmtime(&time_);
 | 
					 | 
				
			||||||
      if (tm) tm_ = *tm;
 | 
					 | 
				
			||||||
      return tm != FMT_NULL;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  dispatcher gt(time);
 | 
					 | 
				
			||||||
  // Too big time values may be unsupported.
 | 
					 | 
				
			||||||
  if (!gt.run())
 | 
					 | 
				
			||||||
    FMT_THROW(format_error("time_t value out of range"));
 | 
					 | 
				
			||||||
  return gt.tm_;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace internal {
 | 
					 | 
				
			||||||
inline std::size_t strftime(char *str, std::size_t count, const char *format,
 | 
					 | 
				
			||||||
                            const std::tm *time) {
 | 
					 | 
				
			||||||
  return std::strftime(str, count, format, time);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
inline std::size_t strftime(wchar_t *str, std::size_t count,
 | 
					 | 
				
			||||||
                            const wchar_t *format, const std::tm *time) {
 | 
					 | 
				
			||||||
  return std::wcsftime(str, count, format, time);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
template <typename Char>
 | 
					 | 
				
			||||||
struct formatter<std::tm, Char> {
 | 
					 | 
				
			||||||
  template <typename ParseContext>
 | 
					 | 
				
			||||||
  auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
 | 
					 | 
				
			||||||
    auto it = ctx.begin();
 | 
					 | 
				
			||||||
    if (it != ctx.end() && *it == ':')
 | 
					 | 
				
			||||||
      ++it;
 | 
					 | 
				
			||||||
    auto end = it;
 | 
					 | 
				
			||||||
    while (end != ctx.end() && *end != '}')
 | 
					 | 
				
			||||||
      ++end;
 | 
					 | 
				
			||||||
    tm_format.reserve(internal::to_unsigned(end - it + 1));
 | 
					 | 
				
			||||||
    tm_format.append(it, end);
 | 
					 | 
				
			||||||
    tm_format.push_back('\0');
 | 
					 | 
				
			||||||
    return end;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  template <typename FormatContext>
 | 
					 | 
				
			||||||
  auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) {
 | 
					 | 
				
			||||||
    basic_memory_buffer<Char> buf;
 | 
					 | 
				
			||||||
    std::size_t start = buf.size();
 | 
					 | 
				
			||||||
    for (;;) {
 | 
					 | 
				
			||||||
      std::size_t size = buf.capacity() - start;
 | 
					 | 
				
			||||||
      std::size_t count =
 | 
					 | 
				
			||||||
        internal::strftime(&buf[start], size, &tm_format[0], &tm);
 | 
					 | 
				
			||||||
      if (count != 0) {
 | 
					 | 
				
			||||||
        buf.resize(start + count);
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      if (size >= tm_format.size() * 256) {
 | 
					 | 
				
			||||||
        // If the buffer is 256 times larger than the format string, assume
 | 
					 | 
				
			||||||
        // that `strftime` gives an empty result. There doesn't seem to be a
 | 
					 | 
				
			||||||
        // better way to distinguish the two cases:
 | 
					 | 
				
			||||||
        // https://github.com/fmtlib/fmt/issues/367
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      const std::size_t MIN_GROWTH = 10;
 | 
					 | 
				
			||||||
      buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return std::copy(buf.begin(), buf.end(), ctx.out());
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  basic_memory_buffer<Char> tm_format;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
FMT_END_NAMESPACE
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif  // FMT_TIME_H_
 | 
					 | 
				
			||||||
							
								
								
									
										16
									
								
								src/fmt.cpp
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								src/fmt.cpp
									
									
									
									
									
								
							@ -16,21 +16,19 @@ template FMT_API std::locale internal::locale_ref::get<std::locale>() const;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Explicit instantiations for char.
 | 
					// Explicit instantiations for char.
 | 
				
			||||||
template FMT_API char internal::thousands_sep_impl(locale_ref);
 | 
					template FMT_API char internal::thousands_sep_impl(locale_ref);
 | 
				
			||||||
template FMT_API void internal::basic_buffer<char>::append(const char *, const char *);
 | 
					template FMT_API char internal::decimal_point_impl(locale_ref);
 | 
				
			||||||
 | 
					template FMT_API void internal::buffer<char>::append(const char *, const char *);
 | 
				
			||||||
template FMT_API void internal::arg_map<format_context>::init(const basic_format_args<format_context> &args);
 | 
					template FMT_API void internal::arg_map<format_context>::init(const basic_format_args<format_context> &args);
 | 
				
			||||||
template FMT_API int internal::char_traits<char>::format_float(char *, std::size_t, const char *, int, double);
 | 
					 | 
				
			||||||
template FMT_API int internal::char_traits<char>::format_float(char *, std::size_t, const char *, int, long double);
 | 
					 | 
				
			||||||
template FMT_API std::string internal::vformat<char>(string_view, basic_format_args<format_context>);
 | 
					template FMT_API std::string internal::vformat<char>(string_view, basic_format_args<format_context>);
 | 
				
			||||||
template FMT_API format_context::iterator internal::vformat_to(internal::buffer &, string_view, basic_format_args<format_context>);
 | 
					template FMT_API format_context::iterator internal::vformat_to(internal::buffer<char> &, string_view, basic_format_args<format_context>);
 | 
				
			||||||
template FMT_API void internal::sprintf_format(double, internal::buffer &, core_format_specs);
 | 
					template FMT_API char* internal::sprintf_format(double, internal::buffer<char> &, sprintf_specs);
 | 
				
			||||||
template FMT_API void internal::sprintf_format(long double, internal::buffer &, core_format_specs);
 | 
					template FMT_API char* internal::sprintf_format(long double, internal::buffer<char> &, sprintf_specs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Explicit instantiations for wchar_t.
 | 
					// Explicit instantiations for wchar_t.
 | 
				
			||||||
template FMT_API wchar_t internal::thousands_sep_impl(locale_ref);
 | 
					template FMT_API wchar_t internal::thousands_sep_impl(locale_ref);
 | 
				
			||||||
template FMT_API void internal::basic_buffer<wchar_t>::append(const wchar_t *, const wchar_t *);
 | 
					template FMT_API wchar_t internal::decimal_point_impl(locale_ref);
 | 
				
			||||||
 | 
					template FMT_API void internal::buffer<wchar_t>::append(const wchar_t *, const wchar_t *);
 | 
				
			||||||
template FMT_API void internal::arg_map<wformat_context>::init(const basic_format_args<wformat_context> &);
 | 
					template FMT_API void internal::arg_map<wformat_context>::init(const basic_format_args<wformat_context> &);
 | 
				
			||||||
template FMT_API int internal::char_traits<wchar_t>::format_float(wchar_t *, std::size_t, const wchar_t *, int, double);
 | 
					 | 
				
			||||||
template FMT_API int internal::char_traits<wchar_t>::format_float(wchar_t *, std::size_t, const wchar_t *, int, long double);
 | 
					 | 
				
			||||||
template FMT_API std::wstring internal::vformat<wchar_t>(wstring_view, basic_format_args<wformat_context>);
 | 
					template FMT_API std::wstring internal::vformat<wchar_t>(wstring_view, basic_format_args<wformat_context>);
 | 
				
			||||||
FMT_END_NAMESPACE
 | 
					FMT_END_NAMESPACE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user