Commit f4771be7 authored by gabime's avatar gabime

Upgraded to fmt 5.1.0

parent 887326e7
...@@ -19,187 +19,199 @@ ...@@ -19,187 +19,199 @@
#define FMT_VERSION 50100 #define FMT_VERSION 50100
#ifdef __has_feature #ifdef __has_feature
#define FMT_HAS_FEATURE(x) __has_feature(x) # define FMT_HAS_FEATURE(x) __has_feature(x)
#else #else
#define FMT_HAS_FEATURE(x) 0 # define FMT_HAS_FEATURE(x) 0
#endif #endif
#ifdef __has_include #ifdef __has_include
#define FMT_HAS_INCLUDE(x) __has_include(x) # define FMT_HAS_INCLUDE(x) __has_include(x)
#else #else
#define FMT_HAS_INCLUDE(x) 0 # define FMT_HAS_INCLUDE(x) 0
#endif #endif
#ifdef __has_cpp_attribute #ifdef __has_cpp_attribute
#define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) # define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else #else
#define FMT_HAS_CPP_ATTRIBUTE(x) 0 # define FMT_HAS_CPP_ATTRIBUTE(x) 0
#endif #endif
#if defined(__GNUC__) && !defined(__clang__) #if defined(__GNUC__) && !defined(__clang__)
#define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) # define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
#else #else
#define FMT_GCC_VERSION 0 # define FMT_GCC_VERSION 0
#endif #endif
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
#define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION # define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION
#else #else
#define FMT_HAS_GXX_CXX11 0 # define FMT_HAS_GXX_CXX11 0
#endif #endif
#ifdef _MSC_VER #ifdef _MSC_VER
#define FMT_MSC_VER _MSC_VER # define FMT_MSC_VER _MSC_VER
#else #else
#define FMT_MSC_VER 0 # define FMT_MSC_VER 0
#endif #endif
// Check if relaxed c++14 constexpr is supported. // Check if relaxed c++14 constexpr is supported.
// GCC doesn't allow throw in constexpr until version 6 (bug 67371). // GCC doesn't allow throw in constexpr until version 6 (bug 67371).
#ifndef FMT_USE_CONSTEXPR #ifndef FMT_USE_CONSTEXPR
#define FMT_USE_CONSTEXPR \ # define FMT_USE_CONSTEXPR \
(FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \
(FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L))
#endif #endif
#if FMT_USE_CONSTEXPR #if FMT_USE_CONSTEXPR
#define FMT_CONSTEXPR constexpr # define FMT_CONSTEXPR constexpr
#define FMT_CONSTEXPR_DECL constexpr # define FMT_CONSTEXPR_DECL constexpr
#else #else
#define FMT_CONSTEXPR inline # define FMT_CONSTEXPR inline
#define FMT_CONSTEXPR_DECL # define FMT_CONSTEXPR_DECL
#endif #endif
#ifndef FMT_OVERRIDE #ifndef FMT_OVERRIDE
#if FMT_HAS_FEATURE(cxx_override) || (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 # if FMT_HAS_FEATURE(cxx_override) || \
#define FMT_OVERRIDE override (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \
#else FMT_MSC_VER >= 1900
#define FMT_OVERRIDE # define FMT_OVERRIDE override
#endif # else
# define FMT_OVERRIDE
# endif
#endif #endif
#if FMT_HAS_FEATURE(cxx_explicit_conversions) || FMT_MSC_VER >= 1800 #if FMT_HAS_FEATURE(cxx_explicit_conversions) || \
#define FMT_EXPLICIT explicit FMT_MSC_VER >= 1800
# define FMT_EXPLICIT explicit
#else #else
#define FMT_EXPLICIT # define FMT_EXPLICIT
#endif #endif
#ifndef FMT_NULL #ifndef FMT_NULL
#if FMT_HAS_FEATURE(cxx_nullptr) || (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600 # if FMT_HAS_FEATURE(cxx_nullptr) || \
#define FMT_NULL nullptr (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \
#define FMT_USE_NULLPTR 1 FMT_MSC_VER >= 1600
#else # define FMT_NULL nullptr
#define FMT_NULL NULL # define FMT_USE_NULLPTR 1
#endif # else
# define FMT_NULL NULL
# endif
#endif #endif
#ifndef FMT_USE_NULLPTR #ifndef FMT_USE_NULLPTR
#define FMT_USE_NULLPTR 0 # define FMT_USE_NULLPTR 0
#endif #endif
#if FMT_HAS_CPP_ATTRIBUTE(noreturn) #if FMT_HAS_CPP_ATTRIBUTE(noreturn)
#define FMT_NORETURN [[noreturn]] # define FMT_NORETURN [[noreturn]]
#else #else
#define FMT_NORETURN # define FMT_NORETURN
#endif #endif
// Check if exceptions are disabled. // Check if exceptions are disabled.
#if defined(__GNUC__) && !defined(__EXCEPTIONS) #if defined(__GNUC__) && !defined(__EXCEPTIONS)
#define FMT_EXCEPTIONS 0 # define FMT_EXCEPTIONS 0
#elif FMT_MSC_VER && !_HAS_EXCEPTIONS #elif FMT_MSC_VER && !_HAS_EXCEPTIONS
#define FMT_EXCEPTIONS 0 # define FMT_EXCEPTIONS 0
#endif #endif
#ifndef FMT_EXCEPTIONS #ifndef FMT_EXCEPTIONS
#define FMT_EXCEPTIONS 1 # define FMT_EXCEPTIONS 1
#endif #endif
// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature). // Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature).
#ifndef FMT_USE_NOEXCEPT #ifndef FMT_USE_NOEXCEPT
#define FMT_USE_NOEXCEPT 0 # define FMT_USE_NOEXCEPT 0
#endif #endif
#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 #if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
#define FMT_DETECTED_NOEXCEPT noexcept (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \
FMT_MSC_VER >= 1900
# define FMT_DETECTED_NOEXCEPT noexcept
#else #else
#define FMT_DETECTED_NOEXCEPT throw() # define FMT_DETECTED_NOEXCEPT throw()
#endif #endif
#ifndef FMT_NOEXCEPT #ifndef FMT_NOEXCEPT
#if FMT_EXCEPTIONS # if FMT_EXCEPTIONS
#define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT # define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT
#else # else
#define FMT_NOEXCEPT # define FMT_NOEXCEPT
#endif # endif
#endif #endif
// This is needed because GCC still uses throw() in its headers when exceptions // This is needed because GCC still uses throw() in its headers when exceptions
// are disabled. // are disabled.
#if FMT_GCC_VERSION #if FMT_GCC_VERSION
#define FMT_DTOR_NOEXCEPT FMT_DETECTED_NOEXCEPT # define FMT_DTOR_NOEXCEPT FMT_DETECTED_NOEXCEPT
#else #else
#define FMT_DTOR_NOEXCEPT FMT_NOEXCEPT # define FMT_DTOR_NOEXCEPT FMT_NOEXCEPT
#endif #endif
#ifndef FMT_BEGIN_NAMESPACE #ifndef FMT_BEGIN_NAMESPACE
#if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || FMT_MSC_VER >= 1900 # if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \
#define FMT_INLINE_NAMESPACE inline namespace FMT_MSC_VER >= 1900
#define FMT_END_NAMESPACE \ # define FMT_INLINE_NAMESPACE inline namespace
} \ # define FMT_END_NAMESPACE }}
} # else
#else # define FMT_INLINE_NAMESPACE namespace
#define FMT_INLINE_NAMESPACE namespace # define FMT_END_NAMESPACE } using namespace v5; }
#define FMT_END_NAMESPACE \ # endif
} \ # define FMT_BEGIN_NAMESPACE namespace fmt { FMT_INLINE_NAMESPACE v5 {
using namespace v5; \
}
#endif
#define FMT_BEGIN_NAMESPACE \
namespace fmt { \
FMT_INLINE_NAMESPACE v5 \
{
#endif #endif
#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) #if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
#ifdef FMT_EXPORT # ifdef FMT_EXPORT
#define FMT_API __declspec(dllexport) # define FMT_API __declspec(dllexport)
#elif defined(FMT_SHARED) # elif defined(FMT_SHARED)
#define FMT_API __declspec(dllimport) # define FMT_API __declspec(dllimport)
#endif # endif
#endif #endif
#ifndef FMT_API #ifndef FMT_API
#define FMT_API # define FMT_API
#endif #endif
#ifndef FMT_ASSERT #ifndef FMT_ASSERT
#define FMT_ASSERT(condition, message) assert((condition) && message) # define FMT_ASSERT(condition, message) assert((condition) && message)
#endif #endif
#define FMT_DELETED = delete #define FMT_DELETED = delete
// A macro to disallow the copy construction and assignment. // A macro to disallow the copy construction and assignment.
#define FMT_DISALLOW_COPY_AND_ASSIGN(Type) \ #define FMT_DISALLOW_COPY_AND_ASSIGN(Type) \
Type(const Type &) FMT_DELETED; \ Type(const Type &) FMT_DELETED; \
void operator=(const Type &) FMT_DELETED void operator=(const Type &) FMT_DELETED
// libc++ supports string_view in pre-c++17. // libc++ supports string_view in pre-c++17.
#if (FMT_HAS_INCLUDE(<string_view>) && (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \ #if (FMT_HAS_INCLUDE(<string_view>) && \
(__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \
(defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
#include <string_view> # include <string_view>
#define FMT_USE_STD_STRING_VIEW # define FMT_USE_STD_STRING_VIEW
#elif (FMT_HAS_INCLUDE(<experimental / string_view>) && __cplusplus >= 201402L) #elif (FMT_HAS_INCLUDE(<experimental/string_view>) && \
#include <experimental/string_view> __cplusplus >= 201402L)
#define FMT_USE_EXPERIMENTAL_STRING_VIEW # include <experimental/string_view>
# define FMT_USE_EXPERIMENTAL_STRING_VIEW
#endif #endif
// std::result_of is defined in <functional> in gcc 4.4. // std::result_of is defined in <functional> in gcc 4.4.
#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 404 #if FMT_GCC_VERSION && FMT_GCC_VERSION <= 404
#include <functional> # include <functional>
#endif #endif
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
// An implementation of declval for pre-C++11 compilers such as gcc 4.
namespace internal { namespace internal {
template<typename T>
// An implementation of declval for pre-C++11 compilers such as gcc 4.
template <typename T>
typename std::add_rvalue_reference<T>::type declval() FMT_NOEXCEPT; typename std::add_rvalue_reference<T>::type declval() FMT_NOEXCEPT;
// Casts nonnegative integer to unsigned.
template <typename Int>
FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
FMT_ASSERT(value >= 0, "negative value");
return static_cast<typename std::make_unsigned<Int>::type>(value);
}
} }
/** /**
...@@ -209,484 +221,361 @@ typename std::add_rvalue_reference<T>::type declval() FMT_NOEXCEPT; ...@@ -209,484 +221,361 @@ typename std::add_rvalue_reference<T>::type declval() FMT_NOEXCEPT;
compiled with a different ``-std`` option than the client code (which is not compiled with a different ``-std`` option than the client code (which is not
recommended). recommended).
*/ */
template<typename Char> template <typename Char>
class basic_string_view class basic_string_view {
{ private:
private: const Char *data_;
const Char *data_; size_t size_;
size_t size_;
public:
public: typedef Char char_type;
typedef Char char_type; typedef const Char *iterator;
typedef const Char *iterator;
// Standard basic_string_view type.
// Standard basic_string_view type.
#if defined(FMT_USE_STD_STRING_VIEW) #if defined(FMT_USE_STD_STRING_VIEW)
typedef std::basic_string_view<Char> type; typedef std::basic_string_view<Char> type;
#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW) #elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
typedef std::experimental::basic_string_view<Char> type; typedef std::experimental::basic_string_view<Char> type;
#else #else
struct type struct type {
{ const char *data() const { return FMT_NULL; }
const char *data() const size_t size() const { return 0; }
{ };
return FMT_NULL;
}
size_t size() const
{
return 0;
}
};
#endif #endif
FMT_CONSTEXPR basic_string_view() FMT_NOEXCEPT : data_(FMT_NULL), size_(0) {} FMT_CONSTEXPR basic_string_view() FMT_NOEXCEPT : data_(FMT_NULL), size_(0) {}
/** Constructs a string reference object from a C string and a size. */ /** Constructs a string reference object from a C string and a size. */
FMT_CONSTEXPR basic_string_view(const Char *s, size_t str_size) FMT_NOEXCEPT : data_(s), size_(str_size) {} FMT_CONSTEXPR basic_string_view(const Char *s, size_t count) FMT_NOEXCEPT
: data_(s), size_(count) {}
/**
\rst /**
Constructs a string reference object from a C string computing \rst
the size with ``std::char_traits<Char>::length``. Constructs a string reference object from a C string computing
\endrst the size with ``std::char_traits<Char>::length``.
*/ \endrst
basic_string_view(const Char *s) */
: data_(s) basic_string_view(const Char *s)
, size_(std::char_traits<Char>::length(s)) : data_(s), size_(std::char_traits<Char>::length(s)) {}
{
} /** Constructs a string reference from a ``std::basic_string`` object. */
template <typename Alloc>
/** Constructs a string reference from a ``std::basic_string`` object. */ FMT_CONSTEXPR basic_string_view(
template<typename Alloc> const std::basic_string<Char, Alloc> &s) FMT_NOEXCEPT
FMT_CONSTEXPR basic_string_view(const std::basic_string<Char, Alloc> &s) FMT_NOEXCEPT : data_(s.c_str()), size_(s.size()) : data_(s.c_str()), size_(s.size()) {}
{
} FMT_CONSTEXPR basic_string_view(type s) FMT_NOEXCEPT
: data_(s.data()), size_(s.size()) {}
FMT_CONSTEXPR basic_string_view(type s) FMT_NOEXCEPT : data_(s.data()), size_(s.size()) {}
/** Returns a pointer to the string data. */
/** Returns a pointer to the string data. */ const Char *data() const { return data_; }
const Char *data() const
{ /** Returns the string size. */
return data_; FMT_CONSTEXPR size_t size() const { return size_; }
}
FMT_CONSTEXPR iterator begin() const { return data_; }
/** Returns the string size. */ FMT_CONSTEXPR iterator end() const { return data_ + size_; }
FMT_CONSTEXPR size_t size() const
{ FMT_CONSTEXPR void remove_prefix(size_t n) {
return size_; data_ += n;
} size_ -= n;
}
FMT_CONSTEXPR iterator begin() const
{ // Lexicographically compare this string reference to other.
return data_; int compare(basic_string_view other) const {
} size_t str_size = size_ < other.size_ ? size_ : other.size_;
FMT_CONSTEXPR iterator end() const int result = std::char_traits<Char>::compare(data_, other.data_, str_size);
{ if (result == 0)
return data_ + size_; result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1);
} return result;
}
FMT_CONSTEXPR void remove_prefix(size_t n)
{ friend bool operator==(basic_string_view lhs, basic_string_view rhs) {
data_ += n; return lhs.compare(rhs) == 0;
size_ -= n; }
} friend bool operator!=(basic_string_view lhs, basic_string_view rhs) {
return lhs.compare(rhs) != 0;
// Lexicographically compare this string reference to other. }
int compare(basic_string_view other) const friend bool operator<(basic_string_view lhs, basic_string_view rhs) {
{ return lhs.compare(rhs) < 0;
size_t str_size = size_ < other.size_ ? size_ : other.size_; }
int result = std::char_traits<Char>::compare(data_, other.data_, str_size); friend bool operator<=(basic_string_view lhs, basic_string_view rhs) {
if (result == 0) return lhs.compare(rhs) <= 0;
result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); }
return result; friend bool operator>(basic_string_view lhs, basic_string_view rhs) {
} return lhs.compare(rhs) > 0;
}
friend bool operator==(basic_string_view lhs, basic_string_view rhs) friend bool operator>=(basic_string_view lhs, basic_string_view rhs) {
{ return lhs.compare(rhs) >= 0;
return lhs.compare(rhs) == 0; }
}
friend bool operator!=(basic_string_view lhs, basic_string_view rhs)
{
return lhs.compare(rhs) != 0;
}
friend bool operator<(basic_string_view lhs, basic_string_view rhs)
{
return lhs.compare(rhs) < 0;
}
friend bool operator<=(basic_string_view lhs, basic_string_view rhs)
{
return lhs.compare(rhs) <= 0;
}
friend bool operator>(basic_string_view lhs, basic_string_view rhs)
{
return lhs.compare(rhs) > 0;
}
friend bool operator>=(basic_string_view lhs, basic_string_view rhs)
{
return lhs.compare(rhs) >= 0;
}
}; };
typedef basic_string_view<char> string_view; typedef basic_string_view<char> string_view;
typedef basic_string_view<wchar_t> wstring_view; typedef basic_string_view<wchar_t> wstring_view;
template<typename Context> template <typename Context>
class basic_format_arg; class basic_format_arg;
template<typename Context> template <typename Context>
class basic_format_args; class basic_format_args;
// A formatter for objects of type T. // A formatter for objects of type T.
template<typename T, typename Char = char, typename Enable = void> template <typename T, typename Char = char, typename Enable = void>
struct formatter; struct formatter;
namespace internal { namespace internal {
/** A contiguous memory buffer with an optional growing ability. */ /** A contiguous memory buffer with an optional growing ability. */
template<typename T> template <typename T>
class basic_buffer class basic_buffer {
{ private:
private: FMT_DISALLOW_COPY_AND_ASSIGN(basic_buffer);
FMT_DISALLOW_COPY_AND_ASSIGN(basic_buffer);
T *ptr_;
T *ptr_; std::size_t size_;
std::size_t size_; std::size_t capacity_;
std::size_t capacity_;
protected:
protected: basic_buffer(T *p = FMT_NULL, std::size_t sz = 0, std::size_t cap = 0)
basic_buffer(T *p = FMT_NULL, std::size_t buf_size = 0, std::size_t buf_capacity = 0) FMT_NOEXCEPT : ptr_(p), FMT_NOEXCEPT: ptr_(p), size_(sz), capacity_(cap) {}
size_(buf_size),
capacity_(buf_capacity) /** Sets the buffer data and capacity. */
{ void set(T *buf_data, std::size_t buf_capacity) FMT_NOEXCEPT {
} ptr_ = buf_data;
capacity_ = buf_capacity;
/** Sets the buffer data and capacity. */ }
void set(T *buf_data, std::size_t buf_capacity) FMT_NOEXCEPT
{ /** Increases the buffer capacity to hold at least *capacity* elements. */
ptr_ = buf_data; virtual void grow(std::size_t capacity) = 0;
capacity_ = buf_capacity;
} public:
typedef T value_type;
/** Increases the buffer capacity to hold at least *capacity* elements. */ typedef const T &const_reference;
virtual void grow(std::size_t capacity) = 0;
virtual ~basic_buffer() {}
public:
typedef T value_type; T *begin() FMT_NOEXCEPT { return ptr_; }
typedef const T &const_reference; T *end() FMT_NOEXCEPT { return ptr_ + size_; }
virtual ~basic_buffer() {} /** Returns the size of this buffer. */
std::size_t size() const FMT_NOEXCEPT { return size_; }
T *begin() FMT_NOEXCEPT
{ /** Returns the capacity of this buffer. */
return ptr_; std::size_t capacity() const FMT_NOEXCEPT { return capacity_; }
}
T *end() FMT_NOEXCEPT /** Returns a pointer to the buffer data. */
{ T *data() FMT_NOEXCEPT { return ptr_; }
return ptr_ + size_;
} /** Returns a pointer to the buffer data. */
const T *data() const FMT_NOEXCEPT { return ptr_; }
/** Returns the size of this buffer. */
std::size_t size() const FMT_NOEXCEPT /**
{ Resizes the buffer. If T is a POD type new elements may not be initialized.
return size_; */
} void resize(std::size_t new_size) {
reserve(new_size);
/** Returns the capacity of this buffer. */ size_ = new_size;
std::size_t capacity() const FMT_NOEXCEPT }
{
return capacity_; /** Reserves space to store at least *capacity* elements. */
} void reserve(std::size_t new_capacity) {
if (new_capacity > capacity_)
/** Returns a pointer to the buffer data. */ grow(new_capacity);
T *data() FMT_NOEXCEPT }
{
return ptr_; void push_back(const T &value) {
} reserve(size_ + 1);
ptr_[size_++] = value;
/** Returns a pointer to the buffer data. */ }
const T *data() const FMT_NOEXCEPT
{ /** Appends data to the end of the buffer. */
return ptr_; template <typename U>
} void append(const U *begin, const U *end);
/** T &operator[](std::size_t index) { return ptr_[index]; }
Resizes the buffer. If T is a POD type new elements may not be initialized. const T &operator[](std::size_t index) const { return ptr_[index]; }
*/
void resize(std::size_t new_size)
{
reserve(new_size);
size_ = new_size;
}
/** Reserves space to store at least *buf_capacity* elements. */
void reserve(std::size_t buf_capacity)
{
if (buf_capacity > capacity_)
grow(buf_capacity);
}
void push_back(const T &value)
{
reserve(size_ + 1);
ptr_[size_++] = value;
}
/** Appends data to the end of the buffer. */
template<typename U>
void append(const U *begin, const U *end);
T &operator[](std::size_t index)
{
return ptr_[index];
}
const T &operator[](std::size_t index) const
{
return ptr_[index];
}
}; };
typedef basic_buffer<char> buffer; typedef basic_buffer<char> buffer;
typedef basic_buffer<wchar_t> wbuffer; typedef basic_buffer<wchar_t> wbuffer;
// A container-backed buffer. // A container-backed buffer.
template<typename Container> template <typename Container>
class container_buffer : public basic_buffer<typename Container::value_type> class container_buffer : public basic_buffer<typename Container::value_type> {
{ private:
private: Container &container_;
Container &container_;
protected:
protected: void grow(std::size_t capacity) FMT_OVERRIDE {
void grow(std::size_t capacity) FMT_OVERRIDE container_.resize(capacity);
{ this->set(&container_[0], capacity);
container_.resize(capacity); }
this->set(&container_[0], capacity);
} public:
explicit container_buffer(Container &c)
public: : basic_buffer<typename Container::value_type>(&c[0], c.size(), c.size()),
explicit container_buffer(Container &c) container_(c) {}
: basic_buffer<typename Container::value_type>(&c[0], c.size(), c.size())
, container_(c)
{
}
}; };
struct error_handler struct error_handler {
{ FMT_CONSTEXPR error_handler() {}
FMT_CONSTEXPR error_handler() {} FMT_CONSTEXPR error_handler(const error_handler &) {}
FMT_CONSTEXPR error_handler(const error_handler &) {}
// This function is intentionally not constexpr to give a compile-time error. // This function is intentionally not constexpr to give a compile-time error.
FMT_API void on_error(const char *message); FMT_API void on_error(const char *message);
}; };
// Formatting of wide characters and strings into a narrow output is disallowed: // Formatting of wide characters and strings into a narrow output is disallowed:
// fmt::format("{}", L"test"); // error // fmt::format("{}", L"test"); // error
// To fix this, use a wide format string: // To fix this, use a wide format string:
// fmt::format(L"{}", L"test"); // fmt::format(L"{}", L"test");
template<typename Char> template <typename Char>
inline void require_wchar() inline void require_wchar() {
{ static_assert(
static_assert(std::is_same<wchar_t, Char>::value, "formatting of wide characters into a narrow output is disallowed"); std::is_same<wchar_t, Char>::value,
"formatting of wide characters into a narrow output is disallowed");
} }
template<typename Char> template <typename Char>
struct named_arg_base; struct named_arg_base;
template<typename T, typename Char> template <typename T, typename Char>
struct named_arg; struct named_arg;
template<typename T> template <typename T>
struct is_named_arg : std::false_type struct is_named_arg : std::false_type {};
{
};
template<typename T, typename Char> template <typename T, typename Char>
struct is_named_arg<named_arg<T, Char>> : std::true_type struct is_named_arg<named_arg<T, Char>> : std::true_type {};
{
};
enum type enum type {
{ none_type, named_arg_type,
none_type, // Integer types should go first,
named_arg_type, int_type, uint_type, long_long_type, ulong_long_type, bool_type, char_type,
// Integer types should go first, last_integer_type = char_type,
int_type, // followed by floating-point types.
uint_type, double_type, long_double_type, last_numeric_type = long_double_type,
long_long_type, cstring_type, string_type, pointer_type, custom_type
ulong_long_type,
bool_type,
char_type,
last_integer_type = char_type,
// followed by floating-point types.
double_type,
long_double_type,
last_numeric_type = long_double_type,
cstring_type,
string_type,
pointer_type,
custom_type
}; };
FMT_CONSTEXPR bool is_integral(type t) FMT_CONSTEXPR bool is_integral(type t) {
{ FMT_ASSERT(t != internal::named_arg_type, "invalid argument type");
FMT_ASSERT(t != internal::named_arg_type, "invalid argument type"); return t > internal::none_type && t <= internal::last_integer_type;
return t > internal::none_type && t <= internal::last_integer_type;
} }
FMT_CONSTEXPR bool is_arithmetic(type t) FMT_CONSTEXPR bool is_arithmetic(type t) {
{ FMT_ASSERT(t != internal::named_arg_type, "invalid argument type");
FMT_ASSERT(t != internal::named_arg_type, "invalid argument type"); return t > internal::none_type && t <= internal::last_numeric_type;
return t > internal::none_type && t <= internal::last_numeric_type;
} }
template<typename T, typename Char, bool ENABLE = true> template <typename T, typename Char, bool ENABLE = true>
struct convert_to_int struct convert_to_int {
{ enum {
enum value = !std::is_arithmetic<T>::value && std::is_convertible<T, int>::value
{ };
value = !std::is_arithmetic<T>::value && std::is_convertible<T, int>::value
};
}; };
template<typename Char> template <typename Char>
struct string_value struct string_value {
{ const Char *value;
const Char *value; std::size_t size;
std::size_t size;
}; };
template<typename Context> template <typename Context>
struct custom_value struct custom_value {
{ const void *value;
const void *value; void (*format)(const void *arg, Context &ctx);
void (*format)(const void *arg, Context &ctx);
}; };
// A formatting argument value. // A formatting argument value.
template<typename Context> template <typename Context>
class value class value {
{ public:
public: typedef typename Context::char_type char_type;
typedef typename Context::char_type char_type;
union {
union int int_value;
{ unsigned uint_value;
int int_value; long long long_long_value;
unsigned uint_value; unsigned long long ulong_long_value;
long long long_long_value; double double_value;
unsigned long long ulong_long_value; long double long_double_value;
double double_value; const void *pointer;
long double long_double_value; string_value<char_type> string;
const void *pointer; string_value<signed char> sstring;
string_value<char_type> string; string_value<unsigned char> ustring;
string_value<signed char> sstring; custom_value<Context> custom;
string_value<unsigned char> ustring; };
custom_value<Context> custom;
}; FMT_CONSTEXPR value(int val = 0) : int_value(val) {}
value(unsigned val) { uint_value = val; }
FMT_CONSTEXPR value(int val = 0) value(long long val) { long_long_value = val; }
: int_value(val) value(unsigned long long val) { ulong_long_value = val; }
{ value(double val) { double_value = val; }
} value(long double val) { long_double_value = val; }
value(unsigned val) value(const char_type *val) { string.value = val; }
{ value(const signed char *val) {
uint_value = val; static_assert(std::is_same<char, char_type>::value,
} "incompatible string types");
value(long long val) sstring.value = val;
{ }
long_long_value = val; value(const unsigned char *val) {
} static_assert(std::is_same<char, char_type>::value,
value(unsigned long long val) "incompatible string types");
{ ustring.value = val;
ulong_long_value = val; }
} value(basic_string_view<char_type> val) {
value(double val) string.value = val.data();
{ string.size = val.size();
double_value = val; }
} value(const void *val) { pointer = val; }
value(long double val)
{ template <typename T>
long_double_value = val; explicit value(const T &val) {
} custom.value = &val;
value(const char_type *val) custom.format = &format_custom_arg<T>;
{ }
string.value = val;
} const named_arg_base<char_type> &as_named_arg() {
value(const signed char *val) return *static_cast<const named_arg_base<char_type>*>(pointer);
{ }
static_assert(std::is_same<char, char_type>::value, "incompatible string types");
sstring.value = val; private:
} // Formats an argument of a custom type, such as a user-defined class.
value(const unsigned char *val) template <typename T>
{ static void format_custom_arg(const void *arg, Context &ctx) {
static_assert(std::is_same<char, char_type>::value, "incompatible string types"); // Get the formatter type through the context to allow different contexts
ustring.value = val; // have different extension points, e.g. `formatter<T>` for `format` and
} // `printf_formatter<T>` for `printf`.
value(basic_string_view<char_type> val) typename Context::template formatter_type<T>::type f;
{ auto &&parse_ctx = ctx.parse_context();
string.value = val.data(); parse_ctx.advance_to(f.parse(parse_ctx));
string.size = val.size(); ctx.advance_to(f.format(*static_cast<const T*>(arg), ctx));
} }
value(const void *val)
{
pointer = val;
}
template<typename T>
explicit value(const T &val)
{
custom.value = &val;
custom.format = &format_custom_arg<T>;
}
const named_arg_base<char_type> &as_named_arg()
{
return *static_cast<const named_arg_base<char_type> *>(pointer);
}
private:
// Formats an argument of a custom type, such as a user-defined class.
template<typename T>
static void format_custom_arg(const void *arg, Context &ctx)
{
// Get the formatter type through the context to allow different contexts
// have different extension points, e.g. `formatter<T>` for `format` and
// `printf_formatter<T>` for `printf`.
typename Context::template formatter_type<T>::type f;
auto &&parse_ctx = ctx.parse_context();
parse_ctx.advance_to(f.parse(parse_ctx));
ctx.advance_to(f.format(*static_cast<const T *>(arg), ctx));
}
}; };
template<typename Context, type TYPE> template <typename Context, type TYPE>
struct typed_value : value<Context> struct typed_value : value<Context> {
{ static const type type_tag = TYPE;
static const type type_tag = TYPE;
template<typename T> template <typename T>
FMT_CONSTEXPR typed_value(const T &val) FMT_CONSTEXPR typed_value(const T &val) : value<Context>(val) {}
: value<Context>(val)
{
}
}; };
template<typename Context, typename T> template <typename Context, typename T>
FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T &value); FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T &value);
#define FMT_MAKE_VALUE(TAG, ArgType, ValueType) \ #define FMT_MAKE_VALUE(TAG, ArgType, ValueType) \
template<typename C> \ template <typename C> \
FMT_CONSTEXPR typed_value<C, TAG> make_value(ArgType val) \ FMT_CONSTEXPR typed_value<C, TAG> make_value(ArgType val) { \
{ \ return static_cast<ValueType>(val); \
return static_cast<ValueType>(val); \ }
}
#define FMT_MAKE_VALUE_SAME(TAG, Type) \ #define FMT_MAKE_VALUE_SAME(TAG, Type) \
template<typename C> \ template <typename C> \
FMT_CONSTEXPR typed_value<C, TAG> make_value(Type val) \ FMT_CONSTEXPR typed_value<C, TAG> make_value(Type val) { \
{ \ return val; \
return val; \ }
}
FMT_MAKE_VALUE(bool_type, bool, int) FMT_MAKE_VALUE(bool_type, bool, int)
FMT_MAKE_VALUE(int_type, short, int) FMT_MAKE_VALUE(int_type, short, int)
...@@ -696,10 +585,15 @@ FMT_MAKE_VALUE_SAME(uint_type, unsigned) ...@@ -696,10 +585,15 @@ FMT_MAKE_VALUE_SAME(uint_type, unsigned)
// To minimize the number of types we need to deal with, long is translated // To minimize the number of types we need to deal with, long is translated
// either to int or to long long depending on its size. // either to int or to long long depending on its size.
typedef std::conditional<sizeof(long) == sizeof(int), int, long long>::type long_type; typedef std::conditional<sizeof(long) == sizeof(int), int, long long>::type
FMT_MAKE_VALUE((sizeof(long) == sizeof(int) ? int_type : long_long_type), long, long_type) long_type;
typedef std::conditional<sizeof(unsigned long) == sizeof(unsigned), unsigned, unsigned long long>::type ulong_type; FMT_MAKE_VALUE(
FMT_MAKE_VALUE((sizeof(unsigned long) == sizeof(unsigned) ? uint_type : ulong_long_type), unsigned long, ulong_type) (sizeof(long) == sizeof(int) ? int_type : long_long_type), long, long_type)
typedef std::conditional<sizeof(unsigned long) == sizeof(unsigned),
unsigned, unsigned long long>::type ulong_type;
FMT_MAKE_VALUE(
(sizeof(unsigned long) == sizeof(unsigned) ? uint_type : ulong_long_type),
unsigned long, ulong_type)
FMT_MAKE_VALUE_SAME(long_long_type, long long) FMT_MAKE_VALUE_SAME(long_long_type, long long)
FMT_MAKE_VALUE_SAME(ulong_long_type, unsigned long long) FMT_MAKE_VALUE_SAME(ulong_long_type, unsigned long long)
...@@ -708,11 +602,10 @@ FMT_MAKE_VALUE(uint_type, unsigned char, unsigned) ...@@ -708,11 +602,10 @@ FMT_MAKE_VALUE(uint_type, unsigned char, unsigned)
FMT_MAKE_VALUE(char_type, char, int) FMT_MAKE_VALUE(char_type, char, int)
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
template<typename C> template <typename C>
inline typed_value<C, char_type> make_value(wchar_t val) inline typed_value<C, char_type> make_value(wchar_t val) {
{ require_wchar<typename C::char_type>();
require_wchar<typename C::char_type>(); return static_cast<int>(val);
return static_cast<int>(val);
} }
#endif #endif
...@@ -722,204 +615,170 @@ FMT_MAKE_VALUE_SAME(long_double_type, long double) ...@@ -722,204 +615,170 @@ FMT_MAKE_VALUE_SAME(long_double_type, long double)
// Formatting of wide strings into a narrow buffer and multibyte strings // Formatting of wide strings into a narrow buffer and multibyte strings
// into a wide buffer is disallowed (https://github.com/fmtlib/fmt/pull/606). // into a wide buffer is disallowed (https://github.com/fmtlib/fmt/pull/606).
FMT_MAKE_VALUE(cstring_type, typename C::char_type *, const typename C::char_type *) FMT_MAKE_VALUE(cstring_type, typename C::char_type*,
FMT_MAKE_VALUE(cstring_type, const typename C::char_type *, const typename C::char_type *) const typename C::char_type*)
FMT_MAKE_VALUE(cstring_type, const typename C::char_type*,
FMT_MAKE_VALUE(cstring_type, signed char *, const signed char *) const typename C::char_type*)
FMT_MAKE_VALUE_SAME(cstring_type, const signed char *)
FMT_MAKE_VALUE(cstring_type, unsigned char *, const unsigned char *) FMT_MAKE_VALUE(cstring_type, signed char*, const signed char*)
FMT_MAKE_VALUE_SAME(cstring_type, const unsigned char *) FMT_MAKE_VALUE_SAME(cstring_type, const signed char*)
FMT_MAKE_VALUE(cstring_type, unsigned char*, const unsigned char*)
FMT_MAKE_VALUE_SAME(cstring_type, const unsigned char*)
FMT_MAKE_VALUE_SAME(string_type, basic_string_view<typename C::char_type>) FMT_MAKE_VALUE_SAME(string_type, basic_string_view<typename C::char_type>)
FMT_MAKE_VALUE(string_type, typename basic_string_view<typename C::char_type>::type, basic_string_view<typename C::char_type>) FMT_MAKE_VALUE(string_type,
FMT_MAKE_VALUE(string_type, const std::basic_string<typename C::char_type> &, basic_string_view<typename C::char_type>) typename basic_string_view<typename C::char_type>::type,
FMT_MAKE_VALUE(pointer_type, void *, const void *) basic_string_view<typename C::char_type>)
FMT_MAKE_VALUE_SAME(pointer_type, const void *) FMT_MAKE_VALUE(string_type, const std::basic_string<typename C::char_type>&,
basic_string_view<typename C::char_type>)
FMT_MAKE_VALUE(pointer_type, void*, const void*)
FMT_MAKE_VALUE_SAME(pointer_type, const void*)
#if FMT_USE_NULLPTR #if FMT_USE_NULLPTR
FMT_MAKE_VALUE(pointer_type, std::nullptr_t, const void *) FMT_MAKE_VALUE(pointer_type, std::nullptr_t, const void*)
#endif #endif
// Formatting of arbitrary pointers is disallowed. If you want to output a // Formatting of arbitrary pointers is disallowed. If you want to output a
// pointer cast it to "void *" or "const void *". In particular, this forbids // pointer cast it to "void *" or "const void *". In particular, this forbids
// formatting of "[const] volatile char *" which is printed as bool by // formatting of "[const] volatile char *" which is printed as bool by
// iostreams. // iostreams.
template<typename C, typename T> template <typename C, typename T>
typename std::enable_if<!std::is_same<T, typename C::char_type>::value>::type make_value(const T *) typename std::enable_if<!std::is_same<T, typename C::char_type>::value>::type
{ make_value(const T *) {
static_assert(!sizeof(T), "formatting of non-void pointers is disallowed"); static_assert(!sizeof(T), "formatting of non-void pointers is disallowed");
} }
template<typename C, typename T> template <typename C, typename T>
inline typename std::enable_if<std::is_enum<T>::value && convert_to_int<T, typename C::char_type>::value, typed_value<C, int_type>>::type inline typename std::enable_if<
make_value(const T &val) std::is_enum<T>::value && convert_to_int<T, typename C::char_type>::value,
{ typed_value<C, int_type>>::type
return static_cast<int>(val); make_value(const T &val) { return static_cast<int>(val); }
}
template<typename C, typename T, typename Char = typename C::char_type> template <typename C, typename T, typename Char = typename C::char_type>
inline typename std::enable_if<!convert_to_int<T, Char>::value && !std::is_convertible<T, basic_string_view<Char>>::value, inline typename std::enable_if<
!convert_to_int<T, Char>::value &&
!std::is_convertible<T, basic_string_view<Char>>::value,
// Implicit conversion to std::string is not handled here because it's // Implicit conversion to std::string is not handled here because it's
// unsafe: https://github.com/fmtlib/fmt/issues/729 // unsafe: https://github.com/fmtlib/fmt/issues/729
typed_value<C, custom_type>>::type typed_value<C, custom_type>>::type
make_value(const T &val) make_value(const T &val) { return val; }
{
return val; template <typename C, typename T>
} typed_value<C, named_arg_type>
make_value(const named_arg<T, typename C::char_type> &val) {
template<typename C, typename T> basic_format_arg<C> arg = make_arg<C>(val.value);
typed_value<C, named_arg_type> make_value(const named_arg<T, typename C::char_type> &val) std::memcpy(val.data, &arg, sizeof(arg));
{ return static_cast<const void*>(&val);
basic_format_arg<C> arg = make_arg<C>(val.value);
std::memcpy(val.data, &arg, sizeof(arg));
return static_cast<const void *>(&val);
} }
// Maximum number of arguments with packed types. // Maximum number of arguments with packed types.
enum enum { max_packed_args = 15 };
{
max_packed_args = 15
};
template<typename Context> template <typename Context>
class arg_map; class arg_map;
template<typename> template <typename>
struct result_of; struct result_of;
template<typename F, typename... Args> template <typename F, typename... Args>
struct result_of<F(Args...)> struct result_of<F(Args...)> {
{ // A workaround for gcc 4.4 that doesn't allow F to be a reference.
// A workaround for gcc 4.4 that doesn't allow F to be a reference. typedef typename std::result_of<
typedef typename std::result_of<typename std::remove_reference<F>::type(Args...)>::type type; typename std::remove_reference<F>::type(Args...)>::type type;
}; };
} // namespace internal }
// A formatting argument. It is a trivially copyable/constructible type to // A formatting argument. It is a trivially copyable/constructible type to
// allow storage in basic_memory_buffer. // allow storage in basic_memory_buffer.
template<typename Context> template <typename Context>
class basic_format_arg class basic_format_arg {
{ private:
private: internal::value<Context> value_;
internal::value<Context> value_; internal::type type_;
internal::type type_;
template<typename ContextType, typename T>
friend FMT_CONSTEXPR basic_format_arg<ContextType> internal::make_arg(const T &value);
template<typename Visitor, typename Ctx>
friend FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type visit(Visitor &&vis, basic_format_arg<Ctx> arg);
friend class basic_format_args<Context>;
friend class internal::arg_map<Context>;
typedef typename Context::char_type char_type;
public:
class handle
{
public:
explicit handle(internal::custom_value<Context> custom)
: custom_(custom)
{
}
void format(Context &ctx) const
{
custom_.format(custom_.value, ctx);
}
private:
internal::custom_value<Context> custom_;
};
FMT_CONSTEXPR basic_format_arg()
: type_(internal::none_type)
{
}
FMT_EXPLICIT operator bool() const FMT_NOEXCEPT template <typename ContextType, typename T>
{ friend FMT_CONSTEXPR basic_format_arg<ContextType>
return type_ != internal::none_type; internal::make_arg(const T &value);
}
internal::type type() const template <typename Visitor, typename Ctx>
{ friend FMT_CONSTEXPR typename internal::result_of<Visitor(int)>::type
return type_; visit(Visitor &&vis, basic_format_arg<Ctx> arg);
}
bool is_integral() const friend class basic_format_args<Context>;
{ friend class internal::arg_map<Context>;
return internal::is_integral(type_);
}
bool is_arithmetic() const
{
return internal::is_arithmetic(type_);
}
};
// Parsing context consisting of a format string range being parsed and an typedef typename Context::char_type char_type;
// argument counter for automatic indexing.
template<typename Char, typename ErrorHandler = internal::error_handler>
class basic_parse_context : private ErrorHandler
{
private:
basic_string_view<Char> format_str_;
int next_arg_id_;
public:
typedef Char char_type;
typedef typename basic_string_view<Char>::iterator iterator;
explicit FMT_CONSTEXPR basic_parse_context(basic_string_view<Char> format_str, ErrorHandler eh = ErrorHandler())
: ErrorHandler(eh)
, format_str_(format_str)
, next_arg_id_(0)
{
}
// Returns an iterator to the beginning of the format string range being public:
// parsed. class handle {
FMT_CONSTEXPR iterator begin() const FMT_NOEXCEPT public:
{ explicit handle(internal::custom_value<Context> custom): custom_(custom) {}
return format_str_.begin();
}
// Returns an iterator past the end of the format string range being parsed. void format(Context &ctx) const { custom_.format(custom_.value, ctx); }
FMT_CONSTEXPR iterator end() const FMT_NOEXCEPT
{
return format_str_.end();
}
// Advances the begin iterator to ``it``. private:
FMT_CONSTEXPR void advance_to(iterator it) internal::custom_value<Context> custom_;
{ };
format_str_.remove_prefix(it - begin());
}
// Returns the next argument index. FMT_CONSTEXPR basic_format_arg() : type_(internal::none_type) {}
FMT_CONSTEXPR unsigned next_arg_id();
FMT_CONSTEXPR bool check_arg_id(unsigned)
{
if (next_arg_id_ > 0)
{
on_error("cannot switch from automatic to manual argument indexing");
return false;
}
next_arg_id_ = -1;
return true;
}
void check_arg_id(basic_string_view<Char>) {}
FMT_CONSTEXPR void on_error(const char *message) FMT_EXPLICIT operator bool() const FMT_NOEXCEPT {
{ return type_ != internal::none_type;
ErrorHandler::on_error(message); }
}
FMT_CONSTEXPR ErrorHandler error_handler() const internal::type type() const { return type_; }
{
return *this; bool is_integral() const { return internal::is_integral(type_); }
} bool is_arithmetic() const { return internal::is_arithmetic(type_); }
};
// Parsing context consisting of a format string range being parsed and an
// argument counter for automatic indexing.
template <typename Char, typename ErrorHandler = internal::error_handler>
class basic_parse_context : private ErrorHandler {
private:
basic_string_view<Char> format_str_;
int next_arg_id_;
public:
typedef Char char_type;
typedef typename basic_string_view<Char>::iterator iterator;
explicit FMT_CONSTEXPR basic_parse_context(
basic_string_view<Char> format_str, ErrorHandler eh = ErrorHandler())
: ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {}
// Returns an iterator to the beginning of the format string range being
// parsed.
FMT_CONSTEXPR iterator begin() const FMT_NOEXCEPT {
return format_str_.begin();
}
// Returns an iterator past the end of the format string range being parsed.
FMT_CONSTEXPR iterator end() const FMT_NOEXCEPT { return format_str_.end(); }
// Advances the begin iterator to ``it``.
FMT_CONSTEXPR void advance_to(iterator it) {
format_str_.remove_prefix(internal::to_unsigned(it - begin()));
}
// Returns the next argument index.
FMT_CONSTEXPR unsigned next_arg_id();
FMT_CONSTEXPR bool check_arg_id(unsigned) {
if (next_arg_id_ > 0) {
on_error("cannot switch from automatic to manual argument indexing");
return false;
}
next_arg_id_ = -1;
return true;
}
void check_arg_id(basic_string_view<Char>) {}
FMT_CONSTEXPR void on_error(const char *message) {
ErrorHandler::on_error(message);
}
FMT_CONSTEXPR ErrorHandler error_handler() const { return *this; }
}; };
typedef basic_parse_context<char> parse_context; typedef basic_parse_context<char> parse_context;
...@@ -927,246 +786,195 @@ typedef basic_parse_context<wchar_t> wparse_context; ...@@ -927,246 +786,195 @@ typedef basic_parse_context<wchar_t> wparse_context;
namespace internal { namespace internal {
// A map from argument names to their values for named arguments. // A map from argument names to their values for named arguments.
template<typename Context> template <typename Context>
class arg_map class arg_map {
{ private:
private: FMT_DISALLOW_COPY_AND_ASSIGN(arg_map);
FMT_DISALLOW_COPY_AND_ASSIGN(arg_map);
typedef typename Context::char_type char_type;
struct entry
{
basic_string_view<char_type> name;
basic_format_arg<Context> arg;
};
entry *map_;
unsigned size_;
void push_back(value<Context> val)
{
const internal::named_arg_base<char_type> &named = val.as_named_arg();
map_[size_] = entry{named.name, named.template deserialize<Context>()};
++size_;
}
public: typedef typename Context::char_type char_type;
arg_map()
: map_(FMT_NULL)
, size_(0)
{
}
void init(const basic_format_args<Context> &args);
~arg_map()
{
delete[] map_;
}
basic_format_arg<Context> find(basic_string_view<char_type> name) const struct entry {
{ basic_string_view<char_type> name;
// The list is unsorted, so just return the first matching name. basic_format_arg<Context> arg;
for (entry *it = map_, *end = map_ + size_; it != end; ++it) };
{
if (it->name == name) entry *map_;
return it->arg; unsigned size_;
}
return basic_format_arg<Context>(); void push_back(value<Context> val) {
} const internal::named_arg_base<char_type> &named = val.as_named_arg();
map_[size_] = entry{named.name, named.template deserialize<Context>()};
++size_;
}
public:
arg_map() : map_(FMT_NULL), size_(0) {}
void init(const basic_format_args<Context> &args);
~arg_map() { delete [] map_; }
basic_format_arg<Context> find(basic_string_view<char_type> name) const {
// The list is unsorted, so just return the first matching name.
for (entry *it = map_, *end = map_ + size_; it != end; ++it) {
if (it->name == name)
return it->arg;
}
return basic_format_arg<Context>();
}
}; };
template<typename OutputIt, typename Context, typename Char> template <typename OutputIt, typename Context, typename Char>
class context_base class context_base {
{ public:
public: typedef OutputIt iterator;
typedef OutputIt iterator;
private:
private: basic_parse_context<Char> parse_context_;
basic_parse_context<Char> parse_context_; iterator out_;
iterator out_; basic_format_args<Context> args_;
basic_format_args<Context> args_;
protected:
protected: typedef Char char_type;
typedef Char char_type; typedef basic_format_arg<Context> format_arg;
typedef basic_format_arg<Context> format_arg;
context_base(OutputIt out, basic_string_view<char_type> format_str,
context_base(OutputIt out, basic_string_view<char_type> format_str, basic_format_args<Context> ctx_args) basic_format_args<Context> ctx_args)
: parse_context_(format_str) : parse_context_(format_str), out_(out), args_(ctx_args) {}
, out_(out)
, args_(ctx_args) // Returns the argument with specified index.
{ format_arg do_get_arg(unsigned arg_id) {
} format_arg arg = args_.get(arg_id);
if (!arg)
parse_context_.on_error("argument index out of range");
return arg;
}
// Returns the argument with specified index. // Checks if manual indexing is used and returns the argument with
format_arg do_get_arg(unsigned arg_id) // specified index.
{ format_arg get_arg(unsigned arg_id) {
format_arg arg = args_.get(arg_id); return this->parse_context().check_arg_id(arg_id) ?
if (!arg) this->do_get_arg(arg_id) : format_arg();
parse_context_.on_error("argument index out of range"); }
return arg;
}
// Checks if manual indexing is used and returns the argument with public:
// specified index. basic_parse_context<char_type> &parse_context() {
format_arg get_arg(unsigned arg_id) return parse_context_;
{ }
return this->parse_context().check_arg_id(arg_id) ? this->do_get_arg(arg_id) : format_arg();
}
public: internal::error_handler error_handler() {
basic_parse_context<char_type> &parse_context() return parse_context_.error_handler();
{ }
return parse_context_;
}
internal::error_handler error_handler() void on_error(const char *message) { parse_context_.on_error(message); }
{
return parse_context_.error_handler();
}
void on_error(const char *message) // Returns an iterator to the beginning of the output range.
{ iterator out() { return out_; }
parse_context_.on_error(message); iterator begin() { return out_; } // deprecated
}
// Returns an iterator to the beginning of the output range. // Advances the begin iterator to ``it``.
iterator out() void advance_to(iterator it) { out_ = it; }
{
return out_;
}
iterator begin()
{
return out_;
} // deprecated
// Advances the begin iterator to ``it``.
void advance_to(iterator it)
{
out_ = it;
}
basic_format_args<Context> args() const basic_format_args<Context> args() const { return args_; }
{
return args_;
}
}; };
// Extracts a reference to the container from back_insert_iterator. // Extracts a reference to the container from back_insert_iterator.
template<typename Container> template <typename Container>
inline Container &get_container(std::back_insert_iterator<Container> it) inline Container &get_container(std::back_insert_iterator<Container> it) {
{ typedef std::back_insert_iterator<Container> bi_iterator;
typedef std::back_insert_iterator<Container> bi_iterator; struct accessor: bi_iterator {
struct accessor : bi_iterator accessor(bi_iterator iter) : bi_iterator(iter) {}
{ using bi_iterator::container;
accessor(bi_iterator iter) };
: bi_iterator(iter) return *accessor(it).container;
{
}
using bi_iterator::container;
};
return *accessor(it).container;
} }
} // namespace internal } // namespace internal
// Formatting context. // Formatting context.
template<typename OutputIt, typename Char> template <typename OutputIt, typename Char>
class basic_format_context : public internal::context_base<OutputIt, basic_format_context<OutputIt, Char>, Char> class basic_format_context :
{ public internal::context_base<
public: OutputIt, basic_format_context<OutputIt, Char>, Char> {
/** The character type for the output. */ public:
typedef Char char_type; /** The character type for the output. */
typedef Char char_type;
// using formatter_type = formatter<T, char_type>;
template<typename T> // using formatter_type = formatter<T, char_type>;
struct formatter_type template <typename T>
{ struct formatter_type { typedef formatter<T, char_type> type; };
typedef formatter<T, char_type> type;
}; private:
internal::arg_map<basic_format_context> map_;
private:
internal::arg_map<basic_format_context> map_; FMT_DISALLOW_COPY_AND_ASSIGN(basic_format_context);
FMT_DISALLOW_COPY_AND_ASSIGN(basic_format_context); typedef internal::context_base<OutputIt, basic_format_context, Char> base;
typedef typename base::format_arg format_arg;
typedef internal::context_base<OutputIt, basic_format_context, Char> base; using base::get_arg;
typedef typename base::format_arg format_arg;
using base::get_arg; public:
using typename base::iterator;
public:
using typename base::iterator; /**
Constructs a ``basic_format_context`` object. References to the arguments are
/** stored in the object so make sure they have appropriate lifetimes.
Constructs a ``basic_format_context`` object. References to the arguments are */
stored in the object so make sure they have appropriate lifetimes. basic_format_context(OutputIt out, basic_string_view<char_type> format_str,
*/ basic_format_args<basic_format_context> ctx_args)
basic_format_context(OutputIt out, basic_string_view<char_type> format_str, basic_format_args<basic_format_context> ctx_args) : base(out, format_str, ctx_args) {}
: base(out, format_str, ctx_args)
{ format_arg next_arg() {
} return this->do_get_arg(this->parse_context().next_arg_id());
}
format_arg next_arg() format_arg get_arg(unsigned arg_id) { return this->do_get_arg(arg_id); }
{
return this->do_get_arg(this->parse_context().next_arg_id()); // Checks if manual indexing is used and returns the argument with the
} // specified name.
format_arg get_arg(unsigned arg_id) format_arg get_arg(basic_string_view<char_type> name);
{
return this->do_get_arg(arg_id);
}
// Checks if manual indexing is used and returns the argument with the
// specified name.
format_arg get_arg(basic_string_view<char_type> name);
}; };
template<typename Char> template <typename Char>
struct buffer_context struct buffer_context {
{ typedef basic_format_context<
typedef basic_format_context<std::back_insert_iterator<internal::basic_buffer<Char>>, Char> type; std::back_insert_iterator<internal::basic_buffer<Char>>, Char> type;
}; };
typedef buffer_context<char>::type format_context; typedef buffer_context<char>::type format_context;
typedef buffer_context<wchar_t>::type wformat_context; typedef buffer_context<wchar_t>::type wformat_context;
namespace internal { namespace internal {
template<typename Context, typename T> template <typename Context, typename T>
struct get_type struct get_type {
{ typedef decltype(make_value<Context>(
typedef decltype(make_value<Context>(declval<typename std::decay<T>::type &>())) value_type; declval<typename std::decay<T>::type&>())) value_type;
static const type value = value_type::type_tag; static const type value = value_type::type_tag;
}; };
template<typename Context> template <typename Context>
FMT_CONSTEXPR uint64_t get_types() FMT_CONSTEXPR unsigned long long get_types() { return 0; }
{
return 0;
}
template<typename Context, typename Arg, typename... Args> template <typename Context, typename Arg, typename... Args>
FMT_CONSTEXPR uint64_t get_types() FMT_CONSTEXPR unsigned long long get_types() {
{ return get_type<Context, Arg>::value | (get_types<Context, Args...>() << 4);
return get_type<Context, Arg>::value | (get_types<Context, Args...>() << 4);
} }
template<typename Context, typename T> template <typename Context, typename T>
FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T &value) FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T &value) {
{ basic_format_arg<Context> arg;
basic_format_arg<Context> arg; arg.type_ = get_type<Context, T>::value;
arg.type_ = get_type<Context, T>::value; arg.value_ = make_value<Context>(value);
arg.value_ = make_value<Context>(value); return arg;
return arg;
} }
template<bool IS_PACKED, typename Context, typename T> template <bool IS_PACKED, typename Context, typename T>
inline typename std::enable_if<IS_PACKED, value<Context>>::type make_arg(const T &value) inline typename std::enable_if<IS_PACKED, value<Context>>::type
{ make_arg(const T &value) {
return make_value<Context>(value); return make_value<Context>(value);
} }
template<bool IS_PACKED, typename Context, typename T> template <bool IS_PACKED, typename Context, typename T>
inline typename std::enable_if<!IS_PACKED, basic_format_arg<Context>>::type make_arg(const T &value) inline typename std::enable_if<!IS_PACKED, basic_format_arg<Context>>::type
{ make_arg(const T &value) {
return make_arg<Context>(value); return make_arg<Context>(value);
}
} }
} // namespace internal
/** /**
\rst \rst
...@@ -1175,51 +983,54 @@ inline typename std::enable_if<!IS_PACKED, basic_format_arg<Context>>::type make ...@@ -1175,51 +983,54 @@ inline typename std::enable_if<!IS_PACKED, basic_format_arg<Context>>::type make
such as `~fmt::vformat`. such as `~fmt::vformat`.
\endrst \endrst
*/ */
template<typename Context, typename... Args> template <typename Context, typename ...Args>
class format_arg_store class format_arg_store {
{ private:
private: static const size_t NUM_ARGS = sizeof...(Args);
static const size_t NUM_ARGS = sizeof...(Args);
// Packed is a macro on MinGW so use IS_PACKED instead. // Packed is a macro on MinGW so use IS_PACKED instead.
static const bool IS_PACKED = NUM_ARGS < internal::max_packed_args; static const bool IS_PACKED = NUM_ARGS < internal::max_packed_args;
typedef typename std::conditional<IS_PACKED, internal::value<Context>, basic_format_arg<Context>>::type value_type; typedef typename std::conditional<IS_PACKED,
internal::value<Context>, basic_format_arg<Context>>::type value_type;
// If the arguments are not packed, add one more element to mark the end. // If the arguments are not packed, add one more element to mark the end.
value_type data_[NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1)]; static const size_t DATA_SIZE =
NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1);
value_type data_[DATA_SIZE];
friend class basic_format_args<Context>; friend class basic_format_args<Context>;
static FMT_CONSTEXPR int64_t get_types() static FMT_CONSTEXPR long long get_types() {
{ return IS_PACKED ?
return IS_PACKED ? static_cast<int64_t>(internal::get_types<Context, Args...>()) : -static_cast<int64_t>(NUM_ARGS); static_cast<long long>(internal::get_types<Context, Args...>()) :
} -static_cast<long long>(NUM_ARGS);
}
public: public:
#if FMT_USE_CONSTEXPR #if FMT_USE_CONSTEXPR
static constexpr int64_t TYPES = get_types(); static constexpr long long TYPES = get_types();
#else #else
static const int64_t TYPES; static const long long TYPES;
#endif #endif
#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 405 #if (FMT_GCC_VERSION && FMT_GCC_VERSION <= 405) || \
// Workaround an array initialization bug in gcc 4.5 and earlier. (FMT_MSC_VER && FMT_MSC_VER <= 1800)
format_arg_store(const Args &... args) // Workaround array initialization issues in gcc <= 4.5 and MSVC <= 2013.
{ format_arg_store(const Args &... args) {
data_ = {internal::make_arg<IS_PACKED, Context>(args)...}; value_type init[DATA_SIZE] =
} {internal::make_arg<IS_PACKED, Context>(args)...};
std::memcpy(data_, init, sizeof(init));
}
#else #else
format_arg_store(const Args &... args) format_arg_store(const Args &... args)
: data_{internal::make_arg<IS_PACKED, Context>(args)...} : data_{internal::make_arg<IS_PACKED, Context>(args)...} {}
{
}
#endif #endif
}; };
#if !FMT_USE_CONSTEXPR #if !FMT_USE_CONSTEXPR
template<typename Context, typename... Args> template <typename Context, typename ...Args>
const int64_t format_arg_store<Context, Args...>::TYPES = get_types(); const long long format_arg_store<Context, Args...>::TYPES = get_types();
#endif #endif
/** /**
...@@ -1229,164 +1040,136 @@ const int64_t format_arg_store<Context, Args...>::TYPES = get_types(); ...@@ -1229,164 +1040,136 @@ const int64_t format_arg_store<Context, Args...>::TYPES = get_types();
be omitted in which case it defaults to `~fmt::context`. be omitted in which case it defaults to `~fmt::context`.
\endrst \endrst
*/ */
template<typename Context, typename... Args> template <typename Context, typename ...Args>
inline format_arg_store<Context, Args...> make_format_args(const Args &... args) inline format_arg_store<Context, Args...>
{ make_format_args(const Args & ... args) {
return format_arg_store<Context, Args...>(args...); return format_arg_store<Context, Args...>(args...);
} }
template<typename... Args> template <typename ...Args>
inline format_arg_store<format_context, Args...> make_format_args(const Args &... args) inline format_arg_store<format_context, Args...>
{ make_format_args(const Args & ... args) {
return format_arg_store<format_context, Args...>(args...); return format_arg_store<format_context, Args...>(args...);
} }
/** Formatting arguments. */ /** Formatting arguments. */
template<typename Context> template <typename Context>
class basic_format_args class basic_format_args {
{ public:
public: typedef unsigned size_type;
typedef unsigned size_type; typedef basic_format_arg<Context> format_arg;
typedef basic_format_arg<Context> format_arg;
private:
private: // To reduce compiled code size per formatting function call, types of first
// To reduce compiled code size per formatting function call, types of first // max_packed_args arguments are passed in the types_ field.
// max_packed_args arguments are passed in the types_ field. unsigned long long types_;
uint64_t types_; union {
union // If the number of arguments is less than max_packed_args, the argument
{ // values are stored in values_, otherwise they are stored in args_.
// If the number of arguments is less than max_packed_args, the argument // This is done to reduce compiled code size as storing larger objects
// values are stored in values_, otherwise they are stored in args_. // may require more code (at least on x86-64) even if the same amount of
// This is done to reduce compiled code size as storing larger objects // data is actually copied to stack. It saves ~10% on the bloat test.
// may require more code (at least on x86-64) even if the same amount of const internal::value<Context> *values_;
// data is actually copied to stack. It saves ~10% on the bloat test. const format_arg *args_;
const internal::value<Context> *values_; };
const format_arg *args_;
}; typename internal::type type(unsigned index) const {
unsigned shift = index * 4;
typename internal::type type(unsigned index) const unsigned long long mask = 0xf;
{ return static_cast<typename internal::type>(
unsigned shift = index * 4; (types_ & (mask << shift)) >> shift);
uint64_t mask = 0xf; }
return static_cast<typename internal::type>((types_ & (mask << shift)) >> shift);
} friend class internal::arg_map<Context>;
friend class internal::arg_map<Context>; void set_data(const internal::value<Context> *values) { values_ = values; }
void set_data(const format_arg *args) { args_ = args; }
void set_data(const internal::value<Context> *values)
{ format_arg do_get(size_type index) const {
values_ = values; long long signed_types = static_cast<long long>(types_);
} if (signed_types < 0) {
void set_data(const format_arg *args) unsigned long long num_args = static_cast<unsigned long long>(-signed_types);
{ return index < num_args ? args_[index] : format_arg();
args_ = args; }
} format_arg arg;
if (index > internal::max_packed_args)
format_arg do_get(size_type index) const return arg;
{ arg.type_ = type(index);
int64_t signed_types = static_cast<int64_t>(types_); if (arg.type_ == internal::none_type)
if (signed_types < 0) return arg;
{ internal::value<Context> &val = arg.value_;
uint64_t num_args = -signed_types; val = values_[index];
return index < num_args ? args_[index] : format_arg(); return arg;
} }
format_arg arg;
if (index > internal::max_packed_args) public:
return arg; basic_format_args() : types_(0) {}
arg.type_ = type(index);
if (arg.type_ == internal::none_type) /**
return arg; \rst
internal::value<Context> &val = arg.value_; Constructs a `basic_format_args` object from `~fmt::format_arg_store`.
val = values_[index]; \endrst
return arg; */
} template <typename... Args>
basic_format_args(const format_arg_store<Context, Args...> &store)
public: : types_(static_cast<unsigned long long>(store.TYPES)) {
basic_format_args() set_data(store.data_);
: types_(0) }
{
} /** Returns the argument at specified index. */
format_arg get(size_type index) const {
/** format_arg arg = do_get(index);
\rst return arg.type_ == internal::named_arg_type ?
Constructs a `basic_format_args` object from `~fmt::format_arg_store`. arg.value_.as_named_arg().template deserialize<Context>() : arg;
\endrst }
*/
template<typename... Args> unsigned max_size() const {
basic_format_args(const format_arg_store<Context, Args...> &store) long long signed_types = static_cast<long long>(types_);
: types_(store.TYPES) return static_cast<unsigned>(
{ signed_types < 0 ?
set_data(store.data_); -signed_types : static_cast<long long>(internal::max_packed_args));
} }
/** Returns the argument at specified index. */
format_arg get(size_type index) const
{
format_arg arg = do_get(index);
return arg.type_ == internal::named_arg_type ? arg.value_.as_named_arg().template deserialize<Context>() : arg;
}
unsigned max_size() const
{
int64_t signed_types = static_cast<int64_t>(types_);
return static_cast<unsigned>(signed_types < 0 ? -signed_types : static_cast<int64_t>(internal::max_packed_args));
}
}; };
/** An alias to ``basic_format_args<context>``. */ /** An alias to ``basic_format_args<context>``. */
// It is a separate type rather than a typedef to make symbols readable. // It is a separate type rather than a typedef to make symbols readable.
struct format_args : basic_format_args<format_context> struct format_args: basic_format_args<format_context> {
{ template <typename ...Args>
template<typename... Args> format_args(Args && ... arg)
format_args(Args &&... arg) : basic_format_args<format_context>(std::forward<Args>(arg)...) {}
: basic_format_args<format_context>(std::forward<Args>(arg)...)
{
}
}; };
struct wformat_args : basic_format_args<wformat_context> struct wformat_args : basic_format_args<wformat_context> {
{ template <typename ...Args>
template<typename... Args> wformat_args(Args && ... arg)
wformat_args(Args &&... arg) : basic_format_args<wformat_context>(std::forward<Args>(arg)...) {}
: basic_format_args<wformat_context>(std::forward<Args>(arg)...)
{
}
}; };
namespace internal { namespace internal {
template<typename Char> template <typename Char>
struct named_arg_base struct named_arg_base {
{ basic_string_view<Char> name;
basic_string_view<Char> name;
// Serialized value<context>. // Serialized value<context>.
mutable char data[sizeof(basic_format_arg<format_context>)]; mutable char data[sizeof(basic_format_arg<format_context>)];
named_arg_base(basic_string_view<Char> nm) named_arg_base(basic_string_view<Char> nm) : name(nm) {}
: name(nm)
{
}
template<typename Context> template <typename Context>
basic_format_arg<Context> deserialize() const basic_format_arg<Context> deserialize() const {
{ basic_format_arg<Context> arg;
basic_format_arg<Context> arg; std::memcpy(&arg, data, sizeof(basic_format_arg<Context>));
std::memcpy(&arg, data, sizeof(basic_format_arg<Context>)); return arg;
return arg; }
}
}; };
template<typename T, typename Char> template <typename T, typename Char>
struct named_arg : named_arg_base<Char> struct named_arg : named_arg_base<Char> {
{ const T &value;
const T &value;
named_arg(basic_string_view<Char> name, const T &val) named_arg(basic_string_view<Char> name, const T &val)
: named_arg_base<Char>(name) : named_arg_base<Char>(name), value(val) {}
, value(val)
{
}
}; };
} // namespace internal }
/** /**
\rst \rst
...@@ -1397,93 +1180,73 @@ struct named_arg : named_arg_base<Char> ...@@ -1397,93 +1180,73 @@ struct named_arg : named_arg_base<Char>
fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)); fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23));
\endrst \endrst
*/ */
template<typename T> template <typename T>
inline internal::named_arg<T, char> arg(string_view name, const T &arg) inline internal::named_arg<T, char> arg(string_view name, const T &arg) {
{ return internal::named_arg<T, char>(name, arg);
return internal::named_arg<T, char>(name, arg);
} }
template<typename T> template <typename T>
inline internal::named_arg<T, wchar_t> arg(wstring_view name, const T &arg) inline internal::named_arg<T, wchar_t> arg(wstring_view name, const T &arg) {
{ return internal::named_arg<T, wchar_t>(name, arg);
return internal::named_arg<T, wchar_t>(name, arg);
} }
// This function template is deleted intentionally to disable nested named // This function template is deleted intentionally to disable nested named
// arguments as in ``format("{}", arg("a", arg("b", 42)))``. // arguments as in ``format("{}", arg("a", arg("b", 42)))``.
template<typename S, typename T, typename Char> template <typename S, typename T, typename Char>
void arg(S, internal::named_arg<T, Char>) FMT_DELETED; void arg(S, internal::named_arg<T, Char>) FMT_DELETED;
enum color #ifndef FMT_EXTENDED_COLORS
{ // color and (v)print_colored are deprecated.
black, enum color { black, red, green, yellow, blue, magenta, cyan, white };
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, string_view format, format_args args);
FMT_API void vprint_colored(color c, wstring_view format, wformat_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,
Formats a string and prints it to stdout using ANSI escape sequences to const Args & ... args) {
specify color (experimental). vprint_colored(c, format_str, make_format_args(args...));
Example:
fmt::print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23);
*/
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>
template<typename... Args> inline void print_colored(color c, wstring_view format_str,
inline void print_colored(color c, wstring_view format_str, const Args &... args) const Args & ... args) {
{ vprint_colored(c, format_str, make_format_args<wformat_context>(args...));
vprint_colored(c, format_str, make_format_args<wformat_context>(args...));
} }
#endif
format_context::iterator vformat_to(internal::buffer &buf, string_view format_str, format_args args); format_context::iterator vformat_to(
wformat_context::iterator vformat_to(internal::wbuffer &buf, wstring_view format_str, wformat_args args); internal::buffer &buf, string_view format_str, format_args args);
wformat_context::iterator vformat_to(
internal::wbuffer &buf, wstring_view format_str, wformat_args args);
template<typename Container> template <typename Container>
struct is_contiguous : std::false_type struct is_contiguous : std::false_type {};
{
};
template<typename Char> template <typename Char>
struct is_contiguous<std::basic_string<Char>> : std::true_type struct is_contiguous<std::basic_string<Char>> : std::true_type {};
{
};
template<typename Char> template <typename Char>
struct is_contiguous<internal::basic_buffer<Char>> : std::true_type struct is_contiguous<internal::basic_buffer<Char>> : std::true_type {};
{
};
/** Formats a string and writes the output to ``out``. */ /** Formats a string and writes the output to ``out``. */
template<typename Container> template <typename Container>
typename std::enable_if<is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type vformat_to( typename std::enable_if<
std::back_insert_iterator<Container> out, string_view format_str, format_args args) is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type
{ vformat_to(std::back_insert_iterator<Container> out,
auto &container = internal::get_container(out); string_view format_str, format_args args) {
internal::container_buffer<Container> buf(container); auto& container = internal::get_container(out);
vformat_to(buf, format_str, args); internal::container_buffer<Container> buf(container);
return std::back_inserter(container); vformat_to(buf, format_str, args);
return std::back_inserter(container);
} }
template<typename Container> template <typename Container>
typename std::enable_if<is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type vformat_to( typename std::enable_if<
std::back_insert_iterator<Container> out, wstring_view format_str, wformat_args args) is_contiguous<Container>::value, std::back_insert_iterator<Container>>::type
{ vformat_to(std::back_insert_iterator<Container> out,
auto &container = internal::get_container(out); wstring_view format_str, wformat_args args) {
internal::container_buffer<Container> buf(container); auto& container = internal::get_container(out);
vformat_to(buf, format_str, args); internal::container_buffer<Container> buf(container);
return std::back_inserter(container); vformat_to(buf, format_str, args);
return std::back_inserter(container);
} }
std::string vformat(string_view format_str, format_args args); std::string vformat(string_view format_str, format_args args);
...@@ -1499,20 +1262,18 @@ std::wstring vformat(wstring_view format_str, wformat_args args); ...@@ -1499,20 +1262,18 @@ std::wstring vformat(wstring_view format_str, wformat_args args);
std::string message = fmt::format("The answer is {}", 42); std::string message = fmt::format("The answer is {}", 42);
\endrst \endrst
*/ */
template<typename... Args> template <typename... Args>
inline std::string format(string_view format_str, const Args &... args) inline std::string format(string_view format_str, const Args & ... args) {
{ // This should be just
// This should be just // return vformat(format_str, make_format_args(args...));
// return vformat(format_str, make_format_args(args...)); // but gcc has trouble optimizing the latter, so break it down.
// but gcc has trouble optimizing the latter, so break it down. format_arg_store<format_context, Args...> as{args...};
format_arg_store<format_context, Args...> as{args...}; return vformat(format_str, as);
return vformat(format_str, as);
} }
template<typename... Args> template <typename... Args>
inline std::wstring format(wstring_view format_str, const Args &... args) inline std::wstring format(wstring_view format_str, const Args & ... args) {
{ format_arg_store<wformat_context, Args...> as{args...};
format_arg_store<wformat_context, Args...> as{args...}; return vformat(format_str, as);
return vformat(format_str, as);
} }
FMT_API void vprint(std::FILE *f, string_view format_str, format_args args); FMT_API void vprint(std::FILE *f, string_view format_str, format_args args);
...@@ -1527,21 +1288,19 @@ FMT_API void vprint(std::FILE *f, wstring_view format_str, wformat_args args); ...@@ -1527,21 +1288,19 @@ FMT_API void vprint(std::FILE *f, wstring_view format_str, wformat_args args);
fmt::print(stderr, "Don't {}!", "panic"); fmt::print(stderr, "Don't {}!", "panic");
\endrst \endrst
*/ */
template<typename... Args> template <typename... Args>
inline void print(std::FILE *f, string_view format_str, const Args &... args) inline void print(std::FILE *f, string_view format_str, const Args & ... args) {
{ format_arg_store<format_context, Args...> as(args...);
format_arg_store<format_context, Args...> as(args...); vprint(f, format_str, as);
vprint(f, format_str, as);
} }
/** /**
Prints formatted data to the file *f* which should be in wide-oriented mode set Prints formatted data to the file *f* which should be in wide-oriented mode set
via ``fwide(f, 1)`` or ``_setmode(_fileno(f), _O_U8TEXT)`` on Windows. via ``fwide(f, 1)`` or ``_setmode(_fileno(f), _O_U8TEXT)`` on Windows.
*/ */
template<typename... Args> template <typename... Args>
inline void print(std::FILE *f, wstring_view format_str, const Args &... args) inline void print(std::FILE *f, wstring_view format_str, const Args & ... args) {
{ format_arg_store<wformat_context, Args...> as(args...);
format_arg_store<wformat_context, Args...> as(args...); vprint(f, format_str, as);
vprint(f, format_str, as);
} }
FMT_API void vprint(string_view format_str, format_args args); FMT_API void vprint(string_view format_str, format_args args);
...@@ -1556,19 +1315,17 @@ FMT_API void vprint(wstring_view format_str, wformat_args args); ...@@ -1556,19 +1315,17 @@ FMT_API void vprint(wstring_view format_str, wformat_args args);
fmt::print("Elapsed time: {0:.2f} seconds", 1.23); fmt::print("Elapsed time: {0:.2f} seconds", 1.23);
\endrst \endrst
*/ */
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) {
{ format_arg_store<format_context, Args...> as{args...};
format_arg_store<format_context, Args...> as{args...}; vprint(format_str, as);
vprint(format_str, as);
} }
template<typename... Args> template <typename... Args>
inline void print(wstring_view format_str, const Args &... args) inline void print(wstring_view format_str, const Args & ... args) {
{ format_arg_store<wformat_context, Args...> as(args...);
format_arg_store<wformat_context, Args...> as(args...); vprint(format_str, as);
vprint(format_str, as);
} }
FMT_END_NAMESPACE FMT_END_NAMESPACE
#endif // FMT_CORE_H_ #endif // FMT_CORE_H_
...@@ -17,52 +17,50 @@ ...@@ -17,52 +17,50 @@
#include <climits> #include <climits>
#include <cmath> #include <cmath>
#include <cstdarg> #include <cstdarg>
#include <cstddef> // for std::ptrdiff_t #include <cstddef> // for std::ptrdiff_t
#include <locale> #include <locale>
#if defined(_WIN32) && defined(__MINGW32__) #if defined(_WIN32) && defined(__MINGW32__)
#include <cstring> # include <cstring>
#endif #endif
#if FMT_USE_WINDOWS_H #if FMT_USE_WINDOWS_H
#if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN) # if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN)
#define WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN
#endif # endif
#if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) # if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
#include <windows.h> # include <windows.h>
#else # else
#define NOMINMAX # define NOMINMAX
#include <windows.h> # include <windows.h>
#undef NOMINMAX # undef NOMINMAX
#endif # endif
#endif #endif
#if FMT_EXCEPTIONS #if FMT_EXCEPTIONS
#define FMT_TRY try # define FMT_TRY try
#define FMT_CATCH(x) catch (x) # define FMT_CATCH(x) catch (x)
#else #else
#define FMT_TRY if (true) # define FMT_TRY if (true)
#define FMT_CATCH(x) if (false) # define FMT_CATCH(x) if (false)
#endif #endif
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) # pragma warning(push)
#pragma warning(disable : 4127) // conditional expression is constant # pragma warning(disable: 4127) // conditional expression is constant
#pragma warning(disable : 4702) // unreachable code # pragma warning(disable: 4702) // unreachable code
// Disable deprecation warning for strerror. The latter is not called but // Disable deprecation warning for strerror. The latter is not called but
// MSVC fails to detect it. // MSVC fails to detect it.
#pragma warning(disable : 4996) # pragma warning(disable: 4996)
#endif #endif
// Dummy implementations of strerror_r and strerror_s called if corresponding // Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available. // system functions are not available.
inline fmt::internal::null<> strerror_r(int, char *, ...) inline fmt::internal::null<> strerror_r(int, char *, ...) {
{ return fmt::internal::null<>();
return fmt::internal::null<>();
} }
inline fmt::internal::null<> strerror_s(char *, std::size_t, ...) inline fmt::internal::null<> strerror_s(char *, std::size_t, ...) {
{ return fmt::internal::null<>();
return fmt::internal::null<>();
} }
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
...@@ -70,28 +68,24 @@ FMT_BEGIN_NAMESPACE ...@@ -70,28 +68,24 @@ FMT_BEGIN_NAMESPACE
namespace { namespace {
#ifndef _MSC_VER #ifndef _MSC_VER
#define FMT_SNPRINTF snprintf # define FMT_SNPRINTF snprintf
#else // _MSC_VER #else // _MSC_VER
inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
{ va_list args;
va_list args; va_start(args, format);
va_start(args, format); int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); va_end(args);
va_end(args); return result;
return result;
} }
#define FMT_SNPRINTF fmt_snprintf # define FMT_SNPRINTF fmt_snprintf
#endif // _MSC_VER #endif // _MSC_VER
#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) #if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
#define FMT_SWPRINTF snwprintf # define FMT_SWPRINTF snwprintf
#else #else
#define FMT_SWPRINTF swprintf # define FMT_SWPRINTF swprintf
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) #endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
const char RESET_COLOR[] = "\x1b[0m";
const wchar_t WRESET_COLOR[] = L"\x1b[0m";
typedef void (*FormatFunc)(internal::buffer &, int, string_view); typedef void (*FormatFunc)(internal::buffer &, int, string_view);
// Portable thread-safe version of strerror. // Portable thread-safe version of strerror.
...@@ -103,432 +97,468 @@ typedef void (*FormatFunc)(internal::buffer &, int, string_view); ...@@ -103,432 +97,468 @@ typedef void (*FormatFunc)(internal::buffer &, int, string_view);
// ERANGE - buffer is not large enough to store the error message // ERANGE - buffer is not large enough to store the error message
// other - failure // other - failure
// Buffer should be at least of size 1. // Buffer should be at least of size 1.
int safe_strerror(int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT int safe_strerror(
{ int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer"); FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer");
class dispatcher class dispatcher {
{ private:
private: int error_code_;
int error_code_; char *&buffer_;
char *&buffer_; std::size_t buffer_size_;
std::size_t buffer_size_;
// A noop assignment operator to avoid bogus warnings.
// A noop assignment operator to avoid bogus warnings. void operator=(const dispatcher &) {}
void operator=(const dispatcher &) {}
// Handle the result of XSI-compliant version of strerror_r.
// Handle the result of XSI-compliant version of strerror_r. int handle(int result) {
int handle(int result) // glibc versions before 2.13 return result in errno.
{ return result == -1 ? errno : result;
// glibc versions before 2.13 return result in errno. }
return result == -1 ? errno : result;
}
// Handle the result of GNU-specific version of strerror_r. // Handle the result of GNU-specific version of strerror_r.
int handle(char *message) int handle(char *message) {
{ // If the buffer is full then the message is probably truncated.
// If the buffer is full then the message is probably truncated. if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) return ERANGE;
return ERANGE; buffer_ = message;
buffer_ = message; return 0;
return 0; }
}
// Handle the case when strerror_r is not available. // Handle the case when strerror_r is not available.
int handle(internal::null<>) int handle(internal::null<>) {
{ return fallback(strerror_s(buffer_, buffer_size_, error_code_));
return fallback(strerror_s(buffer_, buffer_size_, error_code_)); }
}
// Fallback to strerror_s when strerror_r is not available. // Fallback to strerror_s when strerror_r is not available.
int fallback(int result) int fallback(int result) {
{ // If the buffer is full then the message is probably truncated.
// If the buffer is full then the message is probably truncated. return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? ERANGE : result; ERANGE : result;
} }
// Fallback to strerror if strerror_r and strerror_s are not available. // Fallback to strerror if strerror_r and strerror_s are not available.
int fallback(internal::null<>) int fallback(internal::null<>) {
{ errno = 0;
errno = 0; buffer_ = strerror(error_code_);
buffer_ = strerror(error_code_); return errno;
return errno; }
}
public: public:
dispatcher(int err_code, char *&buf, std::size_t buf_size) dispatcher(int err_code, char *&buf, std::size_t buf_size)
: error_code_(err_code) : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
, buffer_(buf)
, buffer_size_(buf_size)
{
}
int run() int run() {
{ return handle(strerror_r(error_code_, buffer_, buffer_size_));
return handle(strerror_r(error_code_, buffer_, buffer_size_)); }
} };
}; return dispatcher(error_code, buffer, buffer_size).run();
return dispatcher(error_code, buffer, buffer_size).run();
} }
void format_error_code(internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT void format_error_code(internal::buffer &out, int error_code,
{ string_view message) FMT_NOEXCEPT {
// Report error code making sure that the output fits into // Report error code making sure that the output fits into
// inline_buffer_size to avoid dynamic memory allocation and potential // inline_buffer_size to avoid dynamic memory allocation and potential
// bad_alloc. // bad_alloc.
out.resize(0); out.resize(0);
static const char SEP[] = ": "; static const char SEP[] = ": ";
static const char ERROR_STR[] = "error "; static const char ERROR_STR[] = "error ";
// Subtract 2 to account for terminating null characters in SEP and ERROR_STR. // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
typedef internal::int_traits<int>::main_type main_type; typedef internal::int_traits<int>::main_type main_type;
main_type abs_value = static_cast<main_type>(error_code); main_type abs_value = static_cast<main_type>(error_code);
if (internal::is_negative(error_code)) if (internal::is_negative(error_code)) {
{ abs_value = 0 - abs_value;
abs_value = 0 - abs_value; ++error_code_size;
++error_code_size; }
} error_code_size += internal::count_digits(abs_value);
error_code_size += internal::count_digits(abs_value); writer w(out);
writer w(out); if (message.size() <= inline_buffer_size - error_code_size) {
if (message.size() <= inline_buffer_size - error_code_size) w.write(message);
{ w.write(SEP);
w.write(message); }
w.write(SEP); w.write(ERROR_STR);
} w.write(error_code);
w.write(ERROR_STR); assert(out.size() <= inline_buffer_size);
w.write(error_code);
assert(out.size() <= inline_buffer_size);
} }
void report_error(FormatFunc func, int error_code, string_view message) FMT_NOEXCEPT void report_error(FormatFunc func, int error_code,
{ string_view message) FMT_NOEXCEPT {
memory_buffer full_message; memory_buffer full_message;
func(full_message, error_code, message); func(full_message, error_code, message);
// Use Writer::data instead of Writer::c_str to avoid potential memory // Use Writer::data instead of Writer::c_str to avoid potential memory
// allocation. // allocation.
std::fwrite(full_message.data(), full_message.size(), 1, stderr); std::fwrite(full_message.data(), full_message.size(), 1, stderr);
std::fputc('\n', stderr); std::fputc('\n', stderr);
} }
} // namespace } // namespace
class locale class locale {
{ private:
private: std::locale locale_;
std::locale locale_;
public: public:
explicit locale(std::locale loc = std::locale()) explicit locale(std::locale loc = std::locale()) : locale_(loc) {}
: locale_(loc) std::locale get() { return locale_; }
{
}
std::locale get()
{
return locale_;
}
}; };
template<typename Char> template <typename Char>
FMT_FUNC Char internal::thousands_sep(locale_provider *lp) FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
{ std::locale loc = lp ? lp->locale().get() : std::locale();
std::locale loc = lp ? lp->locale().get() : std::locale(); return std::use_facet<std::numpunct<Char>>(loc).thousands_sep();
return std::use_facet<std::numpunct<Char>>(loc).thousands_sep();
} }
FMT_FUNC void system_error::init(int err_code, string_view format_str, format_args args) FMT_FUNC void system_error::init(
{ int err_code, string_view format_str, format_args args) {
error_code_ = err_code; error_code_ = err_code;
memory_buffer buffer; memory_buffer buffer;
format_system_error(buffer, err_code, vformat(format_str, args)); format_system_error(buffer, err_code, vformat(format_str, args));
std::runtime_error &base = *this; std::runtime_error &base = *this;
base = std::runtime_error(to_string(buffer)); base = std::runtime_error(to_string(buffer));
} }
namespace internal { namespace internal {
template<typename T> template <typename T>
int char_traits<char>::format_float(char *buffer, std::size_t size, const char *format, int precision, T value) int char_traits<char>::format_float(
{ char *buffer, std::size_t size, const char *format, int precision, T value) {
return precision < 0 ? FMT_SNPRINTF(buffer, size, format, value) : FMT_SNPRINTF(buffer, size, format, precision, value); return precision < 0 ?
FMT_SNPRINTF(buffer, size, format, value) :
FMT_SNPRINTF(buffer, size, format, precision, value);
} }
template<typename T> template <typename T>
int char_traits<wchar_t>::format_float(wchar_t *buffer, std::size_t size, const wchar_t *format, int precision, T value) int char_traits<wchar_t>::format_float(
{ wchar_t *buffer, std::size_t size, const wchar_t *format, int precision,
return precision < 0 ? FMT_SWPRINTF(buffer, size, format, value) : FMT_SWPRINTF(buffer, size, format, precision, value); T value) {
return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, value) :
FMT_SWPRINTF(buffer, size, format, precision, value);
} }
template<typename T> template <typename T>
const char basic_data<T>::DIGITS[] = "0001020304050607080910111213141516171819" const char basic_data<T>::DIGITS[] =
"2021222324252627282930313233343536373839" "0001020304050607080910111213141516171819"
"4041424344454647484950515253545556575859" "2021222324252627282930313233343536373839"
"6061626364656667686970717273747576777879" "4041424344454647484950515253545556575859"
"8081828384858687888990919293949596979899"; "6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899";
#define FMT_POWERS_OF_10(factor) \
factor * 10, factor * 100, factor * 1000, factor * 10000, factor * 100000, factor * 1000000, factor * 10000000, factor * 100000000, \ #define FMT_POWERS_OF_10(factor) \
factor * 1000000000 factor * 10, \
factor * 100, \
template<typename T> factor * 1000, \
const uint32_t basic_data<T>::POWERS_OF_10_32[] = {0, FMT_POWERS_OF_10(1)}; factor * 10000, \
factor * 100000, \
factor * 1000000, \
factor * 10000000, \
factor * 100000000, \
factor * 1000000000
template <typename T>
const uint32_t basic_data<T>::POWERS_OF_10_32[] = {
0, FMT_POWERS_OF_10(1)
};
template<typename T> template <typename T>
const uint64_t basic_data<T>::POWERS_OF_10_64[] = {0, FMT_POWERS_OF_10(1), FMT_POWERS_OF_10(1000000000ull), 10000000000000000000ull}; const uint64_t basic_data<T>::POWERS_OF_10_64[] = {
0,
FMT_POWERS_OF_10(1),
FMT_POWERS_OF_10(1000000000ull),
10000000000000000000ull
};
// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340. // Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340.
// These are generated by support/compute-powers.py. // These are generated by support/compute-powers.py.
template<typename T> template <typename T>
const uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = {0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, 0xcf42894a5dce35ea, const uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = {
0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c, 0x8dd01fad907ffc3c, 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, 0xcf42894a5dce35ea,
0xd3515c2831559a83, 0x9d71ac8fada6c9b5, 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57, 0xc21094364dfb5637, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f,
0x9096ea6f3848984f, 0xd77485cb25823ac7, 0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e, 0x84c8d4dfd2c63f3b, 0xbe5691ef416bd60c, 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5,
0xc5dd44271ad3cdba, 0x936b9fcebb25c996, 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126, 0xb5b5ada8aaff80b8, 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57, 0xc21094364dfb5637,
0x87625f056c7c4a8b, 0xc9bcff6034c13053, 0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f, 0xf8a95fcf88747d94, 0x9096ea6f3848984f, 0xd77485cb25823ac7, 0xa086cfcd97bf97f4, 0xef340a98172aace5,
0xb94470938fa89bcf, 0x8a08f0f8bf0f156b, 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06, 0xaa242499697392d3, 0xb23867fb2a35b28e, 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996,
0xfd87b5f28300ca0e, 0xbce5086492111aeb, 0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000, 0xe8d4a51000000000, 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126, 0xb5b5ada8aaff80b8,
0xad78ebc5ac620000, 0x813f3978f8940984, 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068, 0x9f4f2726179a2245, 0x87625f056c7c4a8b, 0xc9bcff6034c13053, 0x964e858c91ba2655, 0xdff9772470297ebd,
0xed63a231d4c4fb27, 0xb0de65388cc8ada8, 0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758, 0xda01ee641a708dea, 0xa6dfbd9fb8e5b88f, 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b,
0xa26da3999aef774a, 0xf209787bb47d6b85, 0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d, 0x952ab45cfa97a0b3, 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06, 0xaa242499697392d3,
0xde469fbd99a05fe3, 0xa59bc234db398c25, 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2, 0xcc20ce9bd35c78a5, 0xfd87b5f28300ca0e, 0xbce5086492111aeb, 0x8cbccc096f5088cc, 0xd1b71758e219652c,
0x98165af37b2153df, 0xe2a0b5dc971f303a, 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410, 0x8bab8eefb6409c1a, 0x9c40000000000000, 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984,
0xd01fef10a657842c, 0x9b10a4e5e9913129, 0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85, 0xbf21e44003acdd2d, 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068, 0x9f4f2726179a2245,
0x8e679c2f5e44ff8f, 0xd433179d9c8cb841, 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b}; 0xed63a231d4c4fb27, 0xb0de65388cc8ada8, 0x83c7088e1aab65db, 0xc45d1df942711d9a,
0x924d692ca61be758, 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85,
0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d, 0x952ab45cfa97a0b3,
0xde469fbd99a05fe3, 0xa59bc234db398c25, 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece,
0x88fcf317f22241e2, 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a,
0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410, 0x8bab8eefb6409c1a,
0xd01fef10a657842c, 0x9b10a4e5e9913129, 0xe7109bfba19c0c9d, 0xac2820d9623bf429,
0x80444b5e7aa7cf85, 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841,
0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b
};
// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding // Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding
// to significands above. // to significands above.
template<typename T> template <typename T>
const int16_t basic_data<T>::POW10_EXPONENTS[] = {-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, -927, -901, const int16_t basic_data<T>::POW10_EXPONENTS[] = {
-874, -847, -821, -794, -768, -741, -715, -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, -343, -316, -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954,
-289, -263, -236, -210, -183, -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, 375, -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661,
402, 428, 455, 481, 508, 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066}; -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369,
-343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77,
FMT_FUNC fp operator*(fp x, fp y) -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216,
{ 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508,
// Multiply 32-bit parts of significands. 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800,
uint64_t mask = (1ULL << 32) - 1; 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066
uint64_t a = x.f >> 32, b = x.f & mask; };
uint64_t c = y.f >> 32, d = y.f & mask;
uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d; template <typename T> const char basic_data<T>::RESET_COLOR[] = "\x1b[0m";
// Compute mid 64-bit of result and round. template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64); FMT_FUNC fp operator*(fp x, fp y) {
// Multiply 32-bit parts of significands.
uint64_t mask = (1ULL << 32) - 1;
uint64_t a = x.f >> 32, b = x.f & mask;
uint64_t c = y.f >> 32, d = y.f & mask;
uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
// Compute mid 64-bit of result and round.
uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64);
} }
FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {
{ const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10)
const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10) int index = static_cast<int>(std::ceil(
int index = static_cast<int>(std::ceil((min_exponent + fp::significand_size - 1) * one_over_log2_10)); (min_exponent + fp::significand_size - 1) * one_over_log2_10));
// Decimal exponent of the first (smallest) cached power of 10. // Decimal exponent of the first (smallest) cached power of 10.
const int first_dec_exp = -348; const int first_dec_exp = -348;
// Difference between two consecutive decimal exponents in cached powers of 10. // Difference between two consecutive decimal exponents in cached powers of 10.
const int dec_exp_step = 8; const int dec_exp_step = 8;
index = (index - first_dec_exp - 1) / dec_exp_step + 1; index = (index - first_dec_exp - 1) / dec_exp_step + 1;
pow10_exponent = first_dec_exp + index * dec_exp_step; pow10_exponent = first_dec_exp + index * dec_exp_step;
return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]); return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
} }
} // namespace internal } // namespace internal
#if FMT_USE_WINDOWS_H #if FMT_USE_WINDOWS_H
FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
{ static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; if (s.size() > INT_MAX)
if (s.size() > INT_MAX) FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG));
FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG)); int s_size = static_cast<int>(s.size());
int s_size = static_cast<int>(s.size()); if (s_size == 0) {
if (s_size == 0) // MultiByteToWideChar does not support zero length, handle separately.
{ buffer_.resize(1);
// MultiByteToWideChar does not support zero length, handle separately. buffer_[0] = 0;
buffer_.resize(1); return;
buffer_[0] = 0; }
return;
} int length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
int length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0); if (length == 0)
if (length == 0) FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
FMT_THROW(windows_error(GetLastError(), ERROR_MSG)); buffer_.resize(length + 1);
buffer_.resize(length + 1); length = MultiByteToWideChar(
length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
if (length == 0) if (length == 0)
FMT_THROW(windows_error(GetLastError(), ERROR_MSG)); FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
buffer_[length] = 0; buffer_[length] = 0;
} }
FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
{ if (int error_code = convert(s)) {
if (int error_code = convert(s)) FMT_THROW(windows_error(error_code,
{ "cannot convert string from UTF-16 to UTF-8"));
FMT_THROW(windows_error(error_code, "cannot convert string from UTF-16 to UTF-8")); }
}
} }
FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
{ if (s.size() > INT_MAX)
if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER;
return ERROR_INVALID_PARAMETER; int s_size = static_cast<int>(s.size());
int s_size = static_cast<int>(s.size()); if (s_size == 0) {
if (s_size == 0) // WideCharToMultiByte does not support zero length, handle separately.
{ buffer_.resize(1);
// WideCharToMultiByte does not support zero length, handle separately. buffer_[0] = 0;
buffer_.resize(1);
buffer_[0] = 0;
return 0;
}
int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
if (length == 0)
return GetLastError();
buffer_.resize(length + 1);
length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
if (length == 0)
return GetLastError();
buffer_[length] = 0;
return 0; return 0;
}
int length = WideCharToMultiByte(
CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
if (length == 0)
return GetLastError();
buffer_.resize(length + 1);
length = WideCharToMultiByte(
CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
if (length == 0)
return GetLastError();
buffer_[length] = 0;
return 0;
} }
FMT_FUNC void windows_error::init(int err_code, string_view format_str, format_args args) FMT_FUNC void windows_error::init(
{ int err_code, string_view format_str, format_args args) {
error_code_ = err_code; error_code_ = err_code;
memory_buffer buffer; memory_buffer buffer;
internal::format_windows_error(buffer, err_code, vformat(format_str, args)); internal::format_windows_error(buffer, err_code, vformat(format_str, args));
std::runtime_error &base = *this; std::runtime_error &base = *this;
base = std::runtime_error(to_string(buffer)); base = std::runtime_error(to_string(buffer));
} }
FMT_FUNC void internal::format_windows_error(internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT FMT_FUNC void internal::format_windows_error(
{ internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
FMT_TRY FMT_TRY {
{ wmemory_buffer buf;
wmemory_buffer buf; buf.resize(inline_buffer_size);
buf.resize(inline_buffer_size); for (;;) {
for (;;) wchar_t *system_message = &buf[0];
{ int result = FormatMessageW(
wchar_t *system_message = &buf[0]; FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, FMT_NULL, error_code, FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), system_message, static_cast<uint32_t>(buf.size()), FMT_NULL); system_message, static_cast<uint32_t>(buf.size()), FMT_NULL);
if (result != 0) if (result != 0) {
{ utf16_to_utf8 utf8_message;
utf16_to_utf8 utf8_message; if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
if (utf8_message.convert(system_message) == ERROR_SUCCESS) writer w(out);
{ w.write(message);
writer w(out); w.write(": ");
w.write(message); w.write(utf8_message);
w.write(": "); return;
w.write(utf8_message);
return;
}
break;
}
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
break; // Can't get error message, report error code instead.
buf.resize(buf.size() * 2);
} }
break;
}
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
break; // Can't get error message, report error code instead.
buf.resize(buf.size() * 2);
} }
FMT_CATCH(...) {} } FMT_CATCH(...) {}
format_error_code(out, error_code, message); format_error_code(out, error_code, message);
} }
#endif // FMT_USE_WINDOWS_H #endif // FMT_USE_WINDOWS_H
FMT_FUNC void format_system_error(internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT FMT_FUNC void format_system_error(
{ internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
FMT_TRY FMT_TRY {
{ memory_buffer buf;
memory_buffer buf; buf.resize(inline_buffer_size);
buf.resize(inline_buffer_size); for (;;) {
for (;;) char *system_message = &buf[0];
{ int result = safe_strerror(error_code, system_message, buf.size());
char *system_message = &buf[0]; if (result == 0) {
int result = safe_strerror(error_code, system_message, buf.size()); writer w(out);
if (result == 0) w.write(message);
{ w.write(": ");
writer w(out); w.write(system_message);
w.write(message); return;
w.write(": "); }
w.write(system_message); if (result != ERANGE)
return; break; // Can't get error message, report error code instead.
} buf.resize(buf.size() * 2);
if (result != ERANGE)
break; // Can't get error message, report error code instead.
buf.resize(buf.size() * 2);
}
} }
FMT_CATCH(...) {} } FMT_CATCH(...) {}
format_error_code(out, error_code, message); format_error_code(out, error_code, message);
} }
template<typename Char> template <typename Char>
void basic_fixed_buffer<Char>::grow(std::size_t) void basic_fixed_buffer<Char>::grow(std::size_t) {
{ FMT_THROW(std::runtime_error("buffer overflow"));
FMT_THROW(std::runtime_error("buffer overflow"));
} }
FMT_FUNC void internal::error_handler::on_error(const char *message) FMT_FUNC void internal::error_handler::on_error(const char *message) {
{ FMT_THROW(format_error(message));
FMT_THROW(format_error(message));
} }
FMT_FUNC void report_system_error(int error_code, fmt::string_view message) FMT_NOEXCEPT FMT_FUNC void report_system_error(
{ int error_code, fmt::string_view message) FMT_NOEXCEPT {
report_error(format_system_error, error_code, message); report_error(format_system_error, error_code, message);
} }
#if FMT_USE_WINDOWS_H #if FMT_USE_WINDOWS_H
FMT_FUNC void report_windows_error(int error_code, fmt::string_view message) FMT_NOEXCEPT FMT_FUNC void report_windows_error(
{ int error_code, fmt::string_view message) FMT_NOEXCEPT {
report_error(internal::format_windows_error, error_code, message); report_error(internal::format_windows_error, error_code, message);
} }
#endif #endif
FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
{ memory_buffer buffer;
memory_buffer buffer; vformat_to(buffer, format_str, args);
vformat_to(buffer, format_str, args); std::fwrite(buffer.data(), 1, buffer.size(), f);
std::fwrite(buffer.data(), 1, buffer.size(), f);
} }
FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) {
{ wmemory_buffer buffer;
wmemory_buffer buffer; vformat_to(buffer, format_str, args);
vformat_to(buffer, format_str, args); std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
} }
FMT_FUNC void vprint(string_view format_str, format_args args) FMT_FUNC void vprint(string_view format_str, format_args args) {
{ vprint(stdout, format_str, args);
vprint(stdout, format_str, args);
} }
FMT_FUNC void vprint(wstring_view format_str, wformat_args args) FMT_FUNC void vprint(wstring_view format_str, wformat_args args) {
{ vprint(stdout, format_str, args);
vprint(stdout, format_str, args);
} }
FMT_FUNC void vprint_colored(color c, string_view format, format_args args) #ifndef FMT_EXTENDED_COLORS
{ FMT_FUNC void vprint_colored(color c, string_view format, format_args args) {
char escape[] = "\x1b[30m"; char escape[] = "\x1b[30m";
escape[3] = static_cast<char>('0' + c); escape[3] = static_cast<char>('0' + c);
std::fputs(escape, stdout); std::fputs(escape, stdout);
vprint(format, args); vprint(format, args);
std::fputs(RESET_COLOR, stdout); std::fputs(internal::data::RESET_COLOR, stdout);
}
FMT_FUNC 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
namespace internal {
FMT_CONSTEXPR void to_esc(uint8_t c, char out[], int offset) {
out[offset + 0] = static_cast<char>('0' + c / 100);
out[offset + 1] = static_cast<char>('0' + c / 10 % 10);
out[offset + 2] = static_cast<char>('0' + c % 10);
} }
} // namespace internal
FMT_FUNC void vprint_colored(color c, wstring_view format, wformat_args args) FMT_FUNC void vprint_rgb(rgb fd, string_view format, format_args args) {
{ char escape_fd[] = "\x1b[38;2;000;000;000m";
wchar_t escape[] = L"\x1b[30m"; internal::to_esc(fd.r, escape_fd, 7);
escape[3] = static_cast<wchar_t>('0' + c); internal::to_esc(fd.g, escape_fd, 11);
std::fputws(escape, stdout); internal::to_esc(fd.b, escape_fd, 15);
vprint(format, args);
std::fputws(WRESET_COLOR, stdout); std::fputs(escape_fd, stdout);
vprint(format, args);
std::fputs(internal::data::RESET_COLOR, stdout);
} }
FMT_FUNC locale locale_provider::locale() FMT_FUNC void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args) {
{ char escape_fd[] = "\x1b[38;2;000;000;000m"; // foreground color
return fmt::locale(); char escape_bg[] = "\x1b[48;2;000;000;000m"; // background color
internal::to_esc(fd.r, escape_fd, 7);
internal::to_esc(fd.g, escape_fd, 11);
internal::to_esc(fd.b, escape_fd, 15);
internal::to_esc(bg.r, escape_bg, 7);
internal::to_esc(bg.g, escape_bg, 11);
internal::to_esc(bg.b, escape_bg, 15);
std::fputs(escape_fd, stdout);
std::fputs(escape_bg, stdout);
vprint(format, args);
std::fputs(internal::data::RESET_COLOR, stdout);
} }
#endif
FMT_FUNC locale locale_provider::locale() { return fmt::locale(); }
FMT_END_NAMESPACE FMT_END_NAMESPACE
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) # pragma warning(pop)
#endif #endif
#endif // FMT_FORMAT_INL_H_ #endif // FMT_FORMAT_INL_H_
// Formatting library for C++
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "fmt/format-inl.h"
namespace fmt {
template struct internal::basic_data<void>;
// Explicit instantiations for char.
template FMT_API char internal::thousands_sep(locale_provider *lp);
template void basic_fixed_buffer<char>::grow(std::size_t);
template 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 *buffer, std::size_t size, const char *format,
unsigned width, int precision, double value);
template FMT_API int internal::char_traits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, long double value);
// Explicit instantiations for wchar_t.
template FMT_API wchar_t internal::thousands_sep(locale_provider *lp);
template void basic_fixed_buffer<wchar_t>::grow(std::size_t);
template void internal::arg_map<wformat_context>::init(const wformat_args &args);
template FMT_API int internal::char_traits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, double value);
template FMT_API int internal::char_traits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, long double value);
} // namespace fmt
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -14,137 +14,128 @@ ...@@ -14,137 +14,128 @@
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;
typedef typename std::basic_streambuf<Char>::int_type int_type; typedef typename std::basic_streambuf<Char>::traits_type traits_type;
typedef typename std::basic_streambuf<Char>::traits_type traits_type;
basic_buffer<Char> &buffer_;
basic_buffer<Char> &buffer_;
public:
public: formatbuf(basic_buffer<Char> &buffer) : buffer_(buffer) {}
formatbuf(basic_buffer<Char> &buffer)
: buffer_(buffer) protected:
{ // The put-area is actually always empty. This makes the implementation
} // simpler and has the advantage that the streambuf and the buffer are always
// in sync and sputc never writes into uninitialized memory. The obvious
protected: // disadvantage is that each call to sputc always results in a (virtual) call
// The put-area is actually always empty. This makes the implementation // to overflow. There is no disadvantage here for sputn since this always
// simpler and has the advantage that the streambuf and the buffer are always // results in a call to xsputn.
// in sync and sputc never writes into uninitialized memory. The obvious
// disadvantage is that each call to sputc always results in a (virtual) call int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
// to overflow. There is no disadvantage here for sputn since this always if (!traits_type::eq_int_type(ch, traits_type::eof()))
// results in a call to xsputn. buffer_.push_back(static_cast<Char>(ch));
return ch;
int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE }
{
if (!traits_type::eq_int_type(ch, traits_type::eof())) std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE {
buffer_.push_back(static_cast<Char>(ch)); buffer_.append(s, s + count);
return ch; return count;
} }
std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE
{
buffer_.append(s, s + 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 std::ostream).
template<typename T, typename Char> template <typename T, typename Char>
class is_streamable class is_streamable {
{ private:
private: template <typename U>
template<typename U> static decltype(
static decltype(internal::declval<test_stream<Char> &>() << internal::declval<U>(), std::true_type()) test(int); internal::declval<test_stream<Char>&>()
<< internal::declval<U>(), std::true_type()) test(int);
template<typename>
static std::false_type test(...); template <typename>
static std::false_type test(...);
typedef decltype(test<T>(0)) result;
typedef decltype(test<T>(0)) result;
public:
// std::string operator<< is not considered user-defined because we handle strings public:
// specially. // std::string operator<< is not considered user-defined because we handle strings
static const bool value = result::value && !std::is_same<T, std::string>::value; // specially.
static const bool value = result::value && !std::is_same<T, std::string>::value;
}; };
// Disable conversion to int if T has an overloaded operator<< which is a free // Disable conversion to int if T has an overloaded operator<< which is a free
// function (not a member of std::ostream). // function (not a member of std::ostream).
template<typename T, typename Char> template <typename T, typename Char>
class convert_to_int<T, Char, true> class convert_to_int<T, Char, true> {
{ public:
public: static const bool value =
static const bool value = convert_to_int<T, Char, false>::value && !is_streamable<T, Char>::value; convert_to_int<T, Char, false>::value && !is_streamable<T, Char>::value;
}; };
// 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, basic_buffer<Char> &buf) {
{ const Char *data = buf.data();
const Char *data = buf.data(); typedef std::make_unsigned<std::streamsize>::type UnsignedStreamSize;
typedef std::make_unsigned<std::streamsize>::type UnsignedStreamSize; UnsignedStreamSize size = buf.size();
UnsignedStreamSize size = buf.size(); UnsignedStreamSize max_size =
UnsignedStreamSize max_size = internal::to_unsigned((std::numeric_limits<std::streamsize>::max)()); internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
do do {
{ UnsignedStreamSize n = size <= max_size ? size : max_size;
UnsignedStreamSize n = size <= max_size ? size : max_size; os.write(data, static_cast<std::streamsize>(n));
os.write(data, static_cast<std::streamsize>(n)); data += n;
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(basic_buffer<Char> &buffer, const T &value) {
{ internal::formatbuf<Char> format_buf(buffer);
internal::formatbuf<Char> format_buf(buffer); 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());
buffer.resize(buffer.size());
} }
// Disable builtin formatting of enums and use operator<< instead. // Disable builtin formatting of enums and use operator<< instead.
template<typename T> template <typename T>
struct format_enum<T, typename std::enable_if<std::is_enum<T>::value>::type> : std::false_type struct format_enum<T,
{ typename std::enable_if<std::is_enum<T>::value>::type> : std::false_type {};
}; } // namespace internal
} // namespace internal
// 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, typename std::enable_if<internal::is_streamable<T, Char>::value>::type> : formatter<basic_string_view<Char>, Char> struct formatter<T, Char,
{ typename std::enable_if<internal::is_streamable<T, Char>::value>::type>
: formatter<basic_string_view<Char>, Char> {
template<typename Context>
auto format(const T &value, Context &ctx) -> decltype(ctx.out())
{
basic_memory_buffer<Char> buffer;
internal::format_value(buffer, value);
basic_string_view<Char> str(buffer.data(), buffer.size());
formatter<basic_string_view<Char>, Char>::format(str, ctx);
return ctx.out();
}
};
template<typename Char> template <typename Context>
inline void vprint( auto format(const T &value, Context &ctx) -> decltype(ctx.out()) {
std::basic_ostream<Char> &os, basic_string_view<Char> format_str, basic_format_args<typename buffer_context<Char>::type> args)
{
basic_memory_buffer<Char> buffer; basic_memory_buffer<Char> buffer;
vformat_to(buffer, format_str, args); internal::format_value(buffer, value);
internal::write(os, buffer); basic_string_view<Char> str(buffer.data(), buffer.size());
formatter<basic_string_view<Char>, Char>::format(str, ctx);
return ctx.out();
}
};
template <typename Char>
inline void vprint(std::basic_ostream<Char> &os,
basic_string_view<Char> format_str,
basic_format_args<typename buffer_context<Char>::type> args) {
basic_memory_buffer<Char> buffer;
vformat_to(buffer, format_str, args);
internal::write(os, buffer);
} }
/** /**
\rst \rst
...@@ -155,17 +146,17 @@ inline void vprint( ...@@ -155,17 +146,17 @@ inline void vprint(
fmt::print(cerr, "Don't {}!", "panic"); fmt::print(cerr, "Don't {}!", "panic");
\endrst \endrst
*/ */
template<typename... Args> template <typename... Args>
inline void print(std::ostream &os, string_view format_str, const Args &... args) inline void print(std::ostream &os, string_view format_str,
{ const Args & ... args) {
vprint<char>(os, format_str, make_format_args<format_context>(args...)); vprint<char>(os, format_str, make_format_args<format_context>(args...));
} }
template<typename... Args> template <typename... Args>
inline void print(std::wostream &os, wstring_view format_str, const Args &... args) inline void print(std::wostream &os, wstring_view format_str,
{ const Args & ... args) {
vprint<wchar_t>(os, format_str, make_format_args<wformat_context>(args...)); vprint<wchar_t>(os, format_str, make_format_args<wformat_context>(args...));
} }
FMT_END_NAMESPACE FMT_END_NAMESPACE
#endif // FMT_OSTREAM_H_ #endif // FMT_OSTREAM_H_
...@@ -10,55 +10,54 @@ ...@@ -10,55 +10,54 @@
#if defined(__MINGW32__) || defined(__CYGWIN__) #if defined(__MINGW32__) || defined(__CYGWIN__)
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/. // Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
#undef __STRICT_ANSI__ # undef __STRICT_ANSI__
#endif #endif
#include <errno.h> #include <errno.h>
#include <fcntl.h> // for O_RDONLY #include <fcntl.h> // for O_RDONLY
#include <locale.h> // for locale_t #include <locale.h> // for locale_t
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> // for strtod_l #include <stdlib.h> // for strtod_l
#include <cstddef> #include <cstddef>
#if defined __APPLE__ || defined(__FreeBSD__) #if defined __APPLE__ || defined(__FreeBSD__)
#include <xlocale.h> // for LC_NUMERIC_MASK on OS X # include <xlocale.h> // for LC_NUMERIC_MASK on OS X
#endif #endif
#include "format.h" #include "format.h"
#ifndef FMT_POSIX #ifndef FMT_POSIX
#if defined(_WIN32) && !defined(__MINGW32__) # if defined(_WIN32) && !defined(__MINGW32__)
// Fix warnings about deprecated symbols. // Fix warnings about deprecated symbols.
#define FMT_POSIX(call) _##call # define FMT_POSIX(call) _##call
#else # else
#define FMT_POSIX(call) call # define FMT_POSIX(call) call
#endif # endif
#endif #endif
// Calls to system functions are wrapped in FMT_SYSTEM for testability. // Calls to system functions are wrapped in FMT_SYSTEM for testability.
#ifdef FMT_SYSTEM #ifdef FMT_SYSTEM
#define FMT_POSIX_CALL(call) FMT_SYSTEM(call) # define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
#else #else
#define FMT_SYSTEM(call) call # define FMT_SYSTEM(call) call
#ifdef _WIN32 # ifdef _WIN32
// Fix warnings about deprecated symbols. // Fix warnings about deprecated symbols.
#define FMT_POSIX_CALL(call) ::_##call # define FMT_POSIX_CALL(call) ::_##call
#else # else
#define FMT_POSIX_CALL(call) ::call # define FMT_POSIX_CALL(call) ::call
#endif # endif
#endif #endif
// Retries the expression while it evaluates to error_result and errno // Retries the expression while it evaluates to error_result and errno
// equals to EINTR. // equals to EINTR.
#ifndef _WIN32 #ifndef _WIN32
#define FMT_RETRY_VAL(result, expression, error_result) \ # define FMT_RETRY_VAL(result, expression, error_result) \
do \ do { \
{ \ result = (expression); \
result = (expression); \ } while (result == error_result && errno == EINTR)
} while (result == error_result && errno == EINTR)
#else #else
#define FMT_RETRY_VAL(result, expression, error_result) result = (expression) # define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
#endif #endif
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
...@@ -90,167 +89,137 @@ FMT_BEGIN_NAMESPACE ...@@ -90,167 +89,137 @@ 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
} Constructs a string reference from an ``std::string`` object.
\endrst
/** */
\rst basic_cstring_view(const std::basic_string<Char> &s) : data_(s.c_str()) {}
Constructs a string reference from an ``std::string`` object.
\endrst /** Returns the pointer to a C string. */
*/ const Char *c_str() const { return data_; }
basic_cstring_view(const std::basic_string<Char> &s)
: data_(s.c_str())
{
}
/** Returns the pointer to a C string. */
const Char *c_str() const
{
return data_;
}
}; };
typedef basic_cstring_view<char> cstring_view; typedef basic_cstring_view<char> cstring_view;
typedef basic_cstring_view<wchar_t> wcstring_view; typedef basic_cstring_view<wchar_t> wcstring_view;
// An error code. // An error code.
class error_code class error_code {
{ private:
private: int value_;
int value_;
public: public:
explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {} explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {}
int get() const FMT_NOEXCEPT int get() const FMT_NOEXCEPT { return value_; }
{
return value_;
}
}; };
// 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) explicit buffered_file(FILE *f) : 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_(FMT_NULL) {}
// 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_DTOR_NOEXCEPT; FMT_API ~buffered_file() FMT_DTOR_NOEXCEPT;
#if !FMT_USE_RVALUE_REFERENCES #if !FMT_USE_RVALUE_REFERENCES
// Emulate a move constructor and a move assignment operator if rvalue // Emulate a move constructor and a move assignment operator if rvalue
// references are not supported. // references are not supported.
private: private:
// A proxy object to emulate a move constructor. // A proxy object to emulate a move constructor.
// It is private to make it impossible call operator Proxy directly. // It is private to make it impossible call operator Proxy directly.
struct Proxy struct Proxy {
{ FILE *file;
FILE *file; };
};
public: public:
// A "move constructor" for moving from a temporary. // A "move constructor" for moving from a temporary.
buffered_file(Proxy p) FMT_NOEXCEPT : file_(p.file) {} buffered_file(Proxy p) FMT_NOEXCEPT : file_(p.file) {}
// A "move constructor" for moving from an lvalue. // A "move constructor" for moving from an lvalue.
buffered_file(buffered_file &f) FMT_NOEXCEPT : file_(f.file_) buffered_file(buffered_file &f) FMT_NOEXCEPT : file_(f.file_) {
{ f.file_ = FMT_NULL;
f.file_ = FMT_NULL; }
}
// A "move assignment operator" for moving from a temporary.
// A "move assignment operator" for moving from a temporary. buffered_file &operator=(Proxy p) {
buffered_file &operator=(Proxy p) close();
{ file_ = p.file;
close(); return *this;
file_ = p.file; }
return *this;
} // A "move assignment operator" for moving from an lvalue.
buffered_file &operator=(buffered_file &other) {
// A "move assignment operator" for moving from an lvalue. close();
buffered_file &operator=(buffered_file &other) file_ = other.file_;
{ other.file_ = FMT_NULL;
close(); return *this;
file_ = other.file_; }
other.file_ = FMT_NULL;
return *this; // Returns a proxy object for moving from a temporary:
} // buffered_file file = buffered_file(...);
operator Proxy() FMT_NOEXCEPT {
// Returns a proxy object for moving from a temporary: Proxy p = {file_};
// buffered_file file = buffered_file(...); file_ = FMT_NULL;
operator Proxy() FMT_NOEXCEPT return p;
{ }
Proxy p = {file_};
file_ = FMT_NULL;
return p;
}
#else #else
private: private:
FMT_DISALLOW_COPY_AND_ASSIGN(buffered_file); FMT_DISALLOW_COPY_AND_ASSIGN(buffered_file);
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_ = FMT_NULL; }
}
buffered_file& operator=(buffered_file &&other) {
buffered_file &operator=(buffered_file &&other) close();
{ file_ = other.file_;
close(); other.file_ = FMT_NULL;
file_ = other.file_; return *this;
other.file_ = FMT_NULL; }
return *this;
}
#endif #endif
// Opens a file. // Opens a file.
FMT_API buffered_file(cstring_view filename, cstring_view mode); FMT_API buffered_file(cstring_view filename, cstring_view mode);
// Closes the file. // Closes the 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 FILE *get() const FMT_NOEXCEPT { return file_; }
{
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...)); }
}
}; };
// A file. Closed file is represented by a file object with descriptor -1. // A file. Closed file is represented by a file object with descriptor -1.
...@@ -259,226 +228,190 @@ public: ...@@ -259,226 +228,190 @@ public:
// closing the file multiple times will cause a crash on Windows rather // closing the file multiple times will cause a crash on Windows rather
// than an exception. You can get standard behavior by overriding the // than an exception. You can get standard behavior by overriding the
// invalid parameter handler with _set_invalid_parameter_handler. // invalid parameter handler with _set_invalid_parameter_handler.
class file class file {
{ private:
private: int fd_; // File descriptor.
int fd_; // File descriptor.
// Constructs a file object with a given descriptor. // Constructs a file object with a given descriptor.
explicit file(int fd) explicit file(int fd) : fd_(fd) {}
: fd_(fd)
{
}
public: public:
// Possible values for the oflag argument to the constructor. // Possible values for the oflag argument to the constructor.
enum enum {
{ RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing. };
};
// Constructs a file object which doesn't represent any file. // Constructs a file object which doesn't represent any file.
file() FMT_NOEXCEPT : fd_(-1) {} file() FMT_NOEXCEPT : fd_(-1) {}
// Opens a file and constructs a file object representing this file. // Opens a file and constructs a file object representing this file.
FMT_API file(cstring_view path, int oflag); FMT_API file(cstring_view path, int oflag);
#if !FMT_USE_RVALUE_REFERENCES #if !FMT_USE_RVALUE_REFERENCES
// Emulate a move constructor and a move assignment operator if rvalue // Emulate a move constructor and a move assignment operator if rvalue
// references are not supported. // references are not supported.
private: private:
// A proxy object to emulate a move constructor. // A proxy object to emulate a move constructor.
// It is private to make it impossible call operator Proxy directly. // It is private to make it impossible call operator Proxy directly.
struct Proxy struct Proxy {
{ int fd;
int fd; };
};
public:
public: // A "move constructor" for moving from a temporary.
// A "move constructor" for moving from a temporary. file(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {}
file(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {}
// A "move constructor" for moving from an lvalue.
// A "move constructor" for moving from an lvalue. file(file &other) FMT_NOEXCEPT : fd_(other.fd_) {
file(file &other) FMT_NOEXCEPT : fd_(other.fd_) other.fd_ = -1;
{ }
other.fd_ = -1;
} // A "move assignment operator" for moving from a temporary.
file &operator=(Proxy p) {
// A "move assignment operator" for moving from a temporary. close();
file &operator=(Proxy p) fd_ = p.fd;
{ return *this;
close(); }
fd_ = p.fd;
return *this; // A "move assignment operator" for moving from an lvalue.
} file &operator=(file &other) {
close();
// A "move assignment operator" for moving from an lvalue. fd_ = other.fd_;
file &operator=(file &other) other.fd_ = -1;
{ return *this;
close(); }
fd_ = other.fd_;
other.fd_ = -1; // Returns a proxy object for moving from a temporary:
return *this; // file f = file(...);
} operator Proxy() FMT_NOEXCEPT {
Proxy p = {fd_};
// Returns a proxy object for moving from a temporary: fd_ = -1;
// file f = file(...); return p;
operator Proxy() FMT_NOEXCEPT }
{
Proxy p = {fd_};
fd_ = -1;
return p;
}
#else #else
private: private:
FMT_DISALLOW_COPY_AND_ASSIGN(file); FMT_DISALLOW_COPY_AND_ASSIGN(file);
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();
{ fd_ = other.fd_;
close(); other.fd_ = -1;
fd_ = other.fd_; return *this;
other.fd_ = -1; }
return *this;
}
#endif #endif
// Destroys the object closing the file it represents if any. // Destroys the object closing the file it represents if any.
FMT_API ~file() FMT_DTOR_NOEXCEPT; FMT_API ~file() FMT_DTOR_NOEXCEPT;
// Returns the file descriptor. // Returns the file descriptor.
int descriptor() const FMT_NOEXCEPT int descriptor() const FMT_NOEXCEPT { return fd_; }
{
return fd_;
}
// Closes the file. // Closes the file.
FMT_API void close(); FMT_API void close();
// Returns the file size. The size has signed type for consistency with // Returns the file size. The size has signed type for consistency with
// stat::st_size. // stat::st_size.
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.
FMT_API static file dup(int fd); FMT_API static file dup(int fd);
// 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); FMT_API void dup2(int fd);
// 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__) #if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
#define FMT_LOCALE !defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__)
# define FMT_LOCALE
#endif #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 _MSC_VER typedef _locale_t locale_t;
typedef _locale_t locale_t;
enum
{
LC_NUMERIC_MASK = LC_NUMERIC
};
static locale_t newlocale(int category_mask, const char *locale, locale_t)
{
return _create_locale(category_mask, locale);
}
static void freelocale(locale_t locale)
{
_free_locale(locale);
}
static double strtod_l(const char *nptr, char **endptr, _locale_t locale)
{
return _strtod_l(nptr, endptr, locale);
}
#endif
locale_t locale_; enum { LC_NUMERIC_MASK = LC_NUMERIC };
FMT_DISALLOW_COPY_AND_ASSIGN(Locale); static locale_t newlocale(int category_mask, const char *locale, locale_t) {
return _create_locale(category_mask, locale);
}
public: static void freelocale(locale_t locale) {
typedef locale_t Type; _free_locale(locale);
}
Locale()
: locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) static double strtod_l(const char *nptr, char **endptr, _locale_t locale) {
{ return _strtod_l(nptr, endptr, locale);
if (!locale_) }
FMT_THROW(system_error(errno, "cannot create locale")); # endif
}
~Locale() locale_t locale_;
{
freelocale(locale_); FMT_DISALLOW_COPY_AND_ASSIGN(Locale);
}
public:
Type get() const typedef locale_t Type;
{
return locale_; Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) {
} if (!locale_)
FMT_THROW(system_error(errno, "cannot create locale"));
// Converts string to floating-point number and advances str past the end }
// of the parsed input. ~Locale() { freelocale(locale_); }
double strtod(const char *&str) const
{ Type get() const { return locale_; }
char *end = FMT_NULL;
double result = strtod_l(str, &end, locale_); // Converts string to floating-point number and advances str past the end
str = end; // of the parsed input.
return result; double strtod(const char *&str) const {
} char *end = FMT_NULL;
double result = strtod_l(str, &end, locale_);
str = end;
return result;
}
}; };
#endif // FMT_LOCALE #endif // FMT_LOCALE
FMT_END_NAMESPACE FMT_END_NAMESPACE
#if !FMT_USE_RVALUE_REFERENCES #if !FMT_USE_RVALUE_REFERENCES
namespace std { namespace std {
// For compatibility with C++98. // For compatibility with C++98.
inline fmt::buffered_file &move(fmt::buffered_file &f) inline fmt::buffered_file &move(fmt::buffered_file &f) { return f; }
{ inline fmt::file &move(fmt::file &f) { return f; }
return f;
}
inline fmt::file &move(fmt::file &f)
{
return f;
} }
} // namespace std
#endif #endif
#endif // FMT_POSIX_H_ #endif // FMT_POSIX_H_
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
#ifndef FMT_PRINTF_H_ #ifndef FMT_PRINTF_H_
#define FMT_PRINTF_H_ #define FMT_PRINTF_H_
#include <algorithm> // std::fill_n #include <algorithm> // std::fill_n
#include <limits> // std::numeric_limits #include <limits> // std::numeric_limits
#include "ostream.h" #include "ostream.h"
...@@ -18,231 +18,193 @@ namespace internal { ...@@ -18,231 +18,193 @@ namespace internal {
// Checks if a value fits in int - used to avoid warnings about comparing // Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers. // signed and unsigned integers.
template<bool IsSigned> template <bool IsSigned>
struct int_checker struct int_checker {
{ template <typename T>
template<typename T> static bool fits_in_int(T value) {
static bool fits_in_int(T value) unsigned max = std::numeric_limits<int>::max();
{ return value <= max;
unsigned max = std::numeric_limits<int>::max(); }
return value <= max; static bool fits_in_int(bool) { return true; }
}
static bool fits_in_int(bool)
{
return true;
}
}; };
template<> template <>
struct int_checker<true> struct int_checker<true> {
{ template <typename T>
template<typename T> static bool fits_in_int(T value) {
static bool fits_in_int(T value) return value >= std::numeric_limits<int>::min() &&
{ value <= std::numeric_limits<int>::max();
return value >= std::numeric_limits<int>::min() && value <= std::numeric_limits<int>::max(); }
} static bool fits_in_int(int) { return true; }
static bool fits_in_int(int)
{
return true;
}
}; };
class printf_precision_handler : public function<int> class printf_precision_handler: public function<int> {
{ public:
public: template <typename T>
template<typename T> typename std::enable_if<std::is_integral<T>::value, int>::type
typename std::enable_if<std::is_integral<T>::value, int>::type operator()(T value) operator()(T value) {
{ if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) FMT_THROW(format_error("number is too big"));
FMT_THROW(format_error("number is too big")); return static_cast<int>(value);
return static_cast<int>(value); }
}
template <typename T>
template<typename T> typename std::enable_if<!std::is_integral<T>::value, int>::type operator()(T) {
typename std::enable_if<!std::is_integral<T>::value, int>::type operator()(T) FMT_THROW(format_error("precision is not integer"));
{ return 0;
FMT_THROW(format_error("precision is not integer")); }
return 0;
}
}; };
// An argument visitor that returns true iff arg is a zero integer. // An argument visitor that returns true iff arg is a zero integer.
class is_zero_int : public function<bool> class is_zero_int: public function<bool> {
{ public:
public: template <typename T>
template<typename T> typename std::enable_if<std::is_integral<T>::value, bool>::type
typename std::enable_if<std::is_integral<T>::value, bool>::type operator()(T value) operator()(T value) { return value == 0; }
{
return value == 0; template <typename T>
} typename std::enable_if<!std::is_integral<T>::value, bool>::type
operator()(T) { return false; }
template<typename T>
typename std::enable_if<!std::is_integral<T>::value, bool>::type operator()(T)
{
return false;
}
}; };
template<typename T> template <typename T>
struct make_unsigned_or_bool : std::make_unsigned<T> struct make_unsigned_or_bool : std::make_unsigned<T> {};
{
};
template<> template <>
struct make_unsigned_or_bool<bool> struct make_unsigned_or_bool<bool> {
{ typedef bool type;
typedef bool type;
}; };
template<typename T, typename Context> template <typename T, typename Context>
class arg_converter : public function<void> class arg_converter: public function<void> {
{ private:
private: typedef typename Context::char_type Char;
typedef typename Context::char_type Char;
basic_format_arg<Context> &arg_;
basic_format_arg<Context> &arg_; typename Context::char_type type_;
typename Context::char_type type_;
public:
public: arg_converter(basic_format_arg<Context> &arg, Char type)
arg_converter(basic_format_arg<Context> &arg, Char type) : arg_(arg), type_(type) {}
: arg_(arg)
, type_(type) void operator()(bool value) {
{ if (type_ != 's')
} operator()<bool>(value);
}
void operator()(bool value)
{ template <typename U>
if (type_ != 's') typename std::enable_if<std::is_integral<U>::value>::type
operator()<bool>(value); operator()(U value) {
} bool is_signed = type_ == 'd' || type_ == 'i';
typedef typename std::conditional<
template<typename U> std::is_same<T, void>::value, U, T>::type TargetType;
typename std::enable_if<std::is_integral<U>::value>::type operator()(U value) if (const_check(sizeof(TargetType) <= sizeof(int))) {
{ // Extra casts are used to silence warnings.
bool is_signed = type_ == 'd' || type_ == 'i'; if (is_signed) {
typedef typename std::conditional<std::is_same<T, void>::value, U, T>::type TargetType; arg_ = internal::make_arg<Context>(
if (const_check(sizeof(TargetType) <= sizeof(int))) static_cast<int>(static_cast<TargetType>(value)));
{ } else {
// Extra casts are used to silence warnings. typedef typename make_unsigned_or_bool<TargetType>::type Unsigned;
if (is_signed) arg_ = internal::make_arg<Context>(
{ static_cast<unsigned>(static_cast<Unsigned>(value)));
arg_ = internal::make_arg<Context>(static_cast<int>(static_cast<TargetType>(value))); }
} } else {
else if (is_signed) {
{ // glibc's printf doesn't sign extend arguments of smaller types:
typedef typename make_unsigned_or_bool<TargetType>::type Unsigned; // std::printf("%lld", -42); // prints "4294967254"
arg_ = internal::make_arg<Context>(static_cast<unsigned>(static_cast<Unsigned>(value))); // but we don't have to do the same because it's a UB.
} arg_ = internal::make_arg<Context>(static_cast<long long>(value));
} } else {
else arg_ = internal::make_arg<Context>(
{ static_cast<typename make_unsigned_or_bool<U>::type>(value));
if (is_signed) }
{ }
// glibc's printf doesn't sign extend arguments of smaller types: }
// std::printf("%lld", -42); // prints "4294967254"
// but we don't have to do the same because it's a UB. template <typename U>
arg_ = internal::make_arg<Context>(static_cast<long long>(value)); typename std::enable_if<!std::is_integral<U>::value>::type operator()(U) {
} // No coversion needed for non-integral types.
else }
{
arg_ = internal::make_arg<Context>(static_cast<typename make_unsigned_or_bool<U>::type>(value));
}
}
}
template<typename U>
typename std::enable_if<!std::is_integral<U>::value>::type operator()(U)
{
// No coversion needed for non-integral types.
}
}; };
// Converts an integer argument to T for printf, if T is an integral type. // Converts an integer argument to T for printf, if T is an integral type.
// If T is void, the argument is converted to corresponding signed or unsigned // If T is void, the argument is converted to corresponding signed or unsigned
// type depending on the type specifier: 'd' and 'i' - signed, other - // type depending on the type specifier: 'd' and 'i' - signed, other -
// unsigned). // unsigned).
template<typename T, typename Context, typename Char> template <typename T, typename Context, typename Char>
void convert_arg(basic_format_arg<Context> &arg, Char type) void convert_arg(basic_format_arg<Context> &arg, Char type) {
{ visit(arg_converter<T, Context>(arg, type), arg);
visit(arg_converter<T, Context>(arg, type), arg);
} }
// Converts an integer argument to char for printf. // Converts an integer argument to char for printf.
template<typename Context> template <typename Context>
class char_converter : public function<void> class char_converter: public function<void> {
{ private:
private: basic_format_arg<Context> &arg_;
basic_format_arg<Context> &arg_;
FMT_DISALLOW_COPY_AND_ASSIGN(char_converter);
public:
explicit char_converter(basic_format_arg<Context> &arg)
: arg_(arg)
{
}
template<typename T> FMT_DISALLOW_COPY_AND_ASSIGN(char_converter);
typename std::enable_if<std::is_integral<T>::value>::type operator()(T value)
{
typedef typename Context::char_type Char;
arg_ = internal::make_arg<Context>(static_cast<Char>(value));
}
template<typename T> public:
typename std::enable_if<!std::is_integral<T>::value>::type operator()(T) explicit char_converter(basic_format_arg<Context> &arg) : arg_(arg) {}
{
// No coversion needed for non-integral types. template <typename T>
} typename std::enable_if<std::is_integral<T>::value>::type
operator()(T value) {
typedef typename Context::char_type Char;
arg_ = internal::make_arg<Context>(static_cast<Char>(value));
}
template <typename T>
typename std::enable_if<!std::is_integral<T>::value>::type operator()(T) {
// No coversion needed for non-integral types.
}
}; };
// Checks if an argument is a valid printf width specifier and sets // Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative. // left alignment if it is negative.
template<typename Char> template <typename Char>
class printf_width_handler : public function<unsigned> class printf_width_handler: public function<unsigned> {
{ private:
private: typedef basic_format_specs<Char> format_specs;
typedef basic_format_specs<Char> format_specs;
format_specs &spec_;
format_specs &spec_;
FMT_DISALLOW_COPY_AND_ASSIGN(printf_width_handler);
FMT_DISALLOW_COPY_AND_ASSIGN(printf_width_handler);
public:
public: explicit printf_width_handler(format_specs &spec) : spec_(spec) {}
explicit printf_width_handler(format_specs &spec)
: spec_(spec) template <typename T>
{ typename std::enable_if<std::is_integral<T>::value, unsigned>::type
} operator()(T value) {
typedef typename internal::int_traits<T>::main_type UnsignedType;
template<typename T> UnsignedType width = static_cast<UnsignedType>(value);
typename std::enable_if<std::is_integral<T>::value, unsigned>::type operator()(T value) if (internal::is_negative(value)) {
{ spec_.align_ = ALIGN_LEFT;
typedef typename internal::int_traits<T>::main_type UnsignedType; width = 0 - width;
UnsignedType width = static_cast<UnsignedType>(value); }
if (internal::is_negative(value)) unsigned int_max = std::numeric_limits<int>::max();
{ if (width > int_max)
spec_.align_ = ALIGN_LEFT; FMT_THROW(format_error("number is too big"));
width = 0 - width; return static_cast<unsigned>(width);
} }
unsigned int_max = std::numeric_limits<int>::max();
if (width > int_max) template <typename T>
FMT_THROW(format_error("number is too big")); typename std::enable_if<!std::is_integral<T>::value, unsigned>::type
return static_cast<unsigned>(width); operator()(T) {
} FMT_THROW(format_error("width is not integer"));
return 0;
template<typename T> }
typename std::enable_if<!std::is_integral<T>::value, unsigned>::type operator()(T)
{
FMT_THROW(format_error("width is not integer"));
return 0;
}
}; };
} // namespace internal } // namespace internal
template<typename Range> template <typename Range>
class printf_arg_formatter; class printf_arg_formatter;
template<typename OutputIt, typename Char, typename ArgFormatter = printf_arg_formatter<back_insert_range<internal::basic_buffer<Char>>>> template <
typename OutputIt, typename Char,
typename ArgFormatter =
printf_arg_formatter<back_insert_range<internal::basic_buffer<Char>>>>
class basic_printf_context; class basic_printf_context;
/** /**
...@@ -250,406 +212,385 @@ class basic_printf_context; ...@@ -250,406 +212,385 @@ class basic_printf_context;
The ``printf`` argument formatter. The ``printf`` argument formatter.
\endrst \endrst
*/ */
template<typename Range> template <typename Range>
class printf_arg_formatter : public internal::function<typename internal::arg_formatter_base<Range>::iterator>, class printf_arg_formatter:
public internal::arg_formatter_base<Range> public internal::function<
{ typename internal::arg_formatter_base<Range>::iterator>,
private: public internal::arg_formatter_base<Range> {
typedef typename Range::value_type char_type; private:
typedef decltype(internal::declval<Range>().begin()) iterator; typedef typename Range::value_type char_type;
typedef internal::arg_formatter_base<Range> base; typedef decltype(internal::declval<Range>().begin()) iterator;
typedef basic_printf_context<iterator, char_type> context_type; typedef internal::arg_formatter_base<Range> base;
typedef basic_printf_context<iterator, char_type> context_type;
context_type &context_;
context_type &context_;
void write_null_pointer(char)
{ void write_null_pointer(char) {
this->spec().type_ = 0; this->spec().type_ = 0;
this->write("(nil)"); this->write("(nil)");
} }
void write_null_pointer(wchar_t) void write_null_pointer(wchar_t) {
{ this->spec().type_ = 0;
this->spec().type_ = 0; this->write(L"(nil)");
this->write(L"(nil)"); }
}
public:
public: typedef typename base::format_specs format_specs;
typedef typename base::format_specs format_specs;
/**
/** \rst
\rst Constructs an argument formatter object.
Constructs an argument formatter object. *buffer* is a reference to the output buffer and *spec* contains format
*buffer* is a reference to the output buffer and *spec* contains format specifier information for standard argument types.
specifier information for standard argument types. \endrst
\endrst */
*/ printf_arg_formatter(internal::basic_buffer<char_type> &buffer,
printf_arg_formatter(internal::basic_buffer<char_type> &buffer, format_specs &spec, context_type &ctx) format_specs &spec, context_type &ctx)
: base(back_insert_range<internal::basic_buffer<char_type>>(buffer), spec) : base(back_insert_range<internal::basic_buffer<char_type>>(buffer), spec),
, context_(ctx) context_(ctx) {}
{
} template <typename T>
typename std::enable_if<std::is_integral<T>::value, iterator>::type
using base::operator(); operator()(T value) {
// MSVC2013 fails to compile separate overloads for bool and char_type so
/** Formats an argument of type ``bool``. */ // use std::is_same instead.
iterator operator()(bool value) if (std::is_same<T, bool>::value) {
{ format_specs &fmt_spec = this->spec();
format_specs &fmt_spec = this->spec(); if (fmt_spec.type_ != 's')
if (fmt_spec.type_ != 's') return base::operator()(value ? 1 : 0);
return (*this)(value ? 1 : 0); fmt_spec.type_ = 0;
fmt_spec.type_ = 0; this->write(value != 0);
this->write(value); } else if (std::is_same<T, char_type>::value) {
return this->out(); format_specs &fmt_spec = this->spec();
} if (fmt_spec.type_ && fmt_spec.type_ != 'c')
return (*this)(static_cast<int>(value));
/** Formats a character. */ fmt_spec.flags_ = 0;
iterator operator()(char_type value) fmt_spec.align_ = ALIGN_RIGHT;
{ return base::operator()(value);
format_specs &fmt_spec = this->spec(); } else {
if (fmt_spec.type_ && fmt_spec.type_ != 'c') return base::operator()(value);
return (*this)(static_cast<int>(value)); }
fmt_spec.flags_ = 0; return this->out();
fmt_spec.align_ = ALIGN_RIGHT; }
return base::operator()(value);
} template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, iterator>::type
/** Formats a null-terminated C string. */ operator()(T value) {
iterator operator()(const char *value) return base::operator()(value);
{ }
if (value)
base::operator()(value); /** Formats a null-terminated C string. */
else if (this->spec().type_ == 'p') iterator operator()(const char *value) {
write_null_pointer(char_type()); if (value)
else base::operator()(value);
this->write("(null)"); else if (this->spec().type_ == 'p')
return this->out(); write_null_pointer(char_type());
} else
this->write("(null)");
/** Formats a null-terminated wide C string. */ return this->out();
iterator operator()(const wchar_t *value) }
{
if (value) /** Formats a null-terminated wide C string. */
base::operator()(value); iterator operator()(const wchar_t *value) {
else if (this->spec().type_ == 'p') if (value)
write_null_pointer(char_type()); base::operator()(value);
else else if (this->spec().type_ == 'p')
this->write(L"(null)"); write_null_pointer(char_type());
return this->out(); else
} this->write(L"(null)");
return this->out();
/** Formats a pointer. */ }
iterator operator()(const void *value)
{ iterator operator()(basic_string_view<char_type> value) {
if (value) return base::operator()(value);
return base::operator()(value); }
this->spec().type_ = 0;
write_null_pointer(char_type()); iterator operator()(monostate value) {
return this->out(); return base::operator()(value);
} }
/** Formats an argument of a custom (user-defined) type. */ /** Formats a pointer. */
iterator operator()(typename basic_format_arg<context_type>::handle handle) iterator operator()(const void *value) {
{ if (value)
handle.format(context_); return base::operator()(value);
return this->out(); this->spec().type_ = 0;
} write_null_pointer(char_type());
return this->out();
}
/** Formats an argument of a custom (user-defined) type. */
iterator operator()(typename basic_format_arg<context_type>::handle handle) {
handle.format(context_);
return this->out();
}
}; };
template<typename T> template <typename T>
struct printf_formatter struct printf_formatter {
{ template <typename ParseContext>
template<typename ParseContext> auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { return ctx.begin(); }
auto parse(ParseContext &ctx) -> decltype(ctx.begin())
{
return ctx.begin();
}
template<typename FormatContext> template <typename FormatContext>
auto format(const T &value, FormatContext &ctx) -> decltype(ctx.out()) auto format(const T &value, FormatContext &ctx) -> decltype(ctx.out()) {
{ internal::format_value(internal::get_container(ctx.out()), value);
internal::format_value(internal::get_container(ctx.out()), value); return ctx.out();
return ctx.out(); }
}
}; };
/** This template formats data and writes the output to a writer. */ /** This template formats data and writes the output to a writer. */
template<typename OutputIt, typename Char, typename ArgFormatter> template <typename OutputIt, typename Char, typename ArgFormatter>
class basic_printf_context : private internal::context_base<OutputIt, basic_printf_context<OutputIt, Char, ArgFormatter>, Char> class basic_printf_context :
{ private internal::context_base<
public: OutputIt, basic_printf_context<OutputIt, Char, ArgFormatter>, Char> {
/** The character type for the output. */ public:
typedef Char char_type; /** The character type for the output. */
typedef Char char_type;
template<typename T>
struct formatter_type template <typename T>
{ struct formatter_type { typedef printf_formatter<T> type; };
typedef printf_formatter<T> type;
}; private:
typedef internal::context_base<OutputIt, basic_printf_context, Char> base;
private: typedef typename base::format_arg format_arg;
typedef internal::context_base<OutputIt, basic_printf_context, Char> base; typedef basic_format_specs<char_type> format_specs;
typedef typename base::format_arg format_arg; typedef internal::null_terminating_iterator<char_type> iterator;
typedef basic_format_specs<char_type> format_specs;
typedef internal::null_terminating_iterator<char_type> iterator; void parse_flags(format_specs &spec, iterator &it);
void parse_flags(format_specs &spec, iterator &it); // Returns the argument with specified index or, if arg_index is equal
// to the maximum unsigned value, the next argument.
// Returns the argument with specified index or, if arg_index is equal format_arg get_arg(
// to the maximum unsigned value, the next argument. iterator it,
format_arg get_arg(iterator it, unsigned arg_index = (std::numeric_limits<unsigned>::max)()); unsigned arg_index = (std::numeric_limits<unsigned>::max)());
// Parses argument index, flags and width and returns the argument index. // Parses argument index, flags and width and returns the argument index.
unsigned parse_header(iterator &it, format_specs &spec); unsigned parse_header(iterator &it, format_specs &spec);
public: public:
/** /**
\rst \rst
Constructs a ``printf_context`` object. References to the arguments and Constructs a ``printf_context`` object. References to the arguments and
the writer are stored in the context object so make sure they have the writer are stored in the context object so make sure they have
appropriate lifetimes. appropriate lifetimes.
\endrst \endrst
*/ */
basic_printf_context(OutputIt out, basic_string_view<char_type> format_str, basic_format_args<basic_printf_context> args) basic_printf_context(OutputIt out, basic_string_view<char_type> format_str,
: base(out, format_str, args) basic_format_args<basic_printf_context> args)
{ : base(out, format_str, args) {}
}
using base::parse_context;
using base::advance_to; using base::out;
using base::out; using base::advance_to;
using base::parse_context;
/** Formats stored arguments and writes the output to the range. */
/** Formats stored arguments and writes the output to the range. */ void format();
void format();
}; };
template<typename OutputIt, typename Char, typename AF> template <typename OutputIt, typename Char, typename AF>
void basic_printf_context<OutputIt, Char, AF>::parse_flags(format_specs &spec, iterator &it) void basic_printf_context<OutputIt, Char, AF>::parse_flags(
{ format_specs &spec, iterator &it) {
for (;;) for (;;) {
{ switch (*it++) {
switch (*it++) case '-':
{ spec.align_ = ALIGN_LEFT;
case '-': break;
spec.align_ = ALIGN_LEFT; case '+':
break; spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
case '+': break;
spec.flags_ |= SIGN_FLAG | PLUS_FLAG; case '0':
break; spec.fill_ = '0';
case '0': break;
spec.fill_ = '0'; case ' ':
break; spec.flags_ |= SIGN_FLAG;
case ' ': break;
spec.flags_ |= SIGN_FLAG; case '#':
break; spec.flags_ |= HASH_FLAG;
case '#': break;
spec.flags_ |= HASH_FLAG; default:
break; --it;
default: return;
--it; }
return; }
}
}
} }
template<typename OutputIt, typename Char, typename AF> template <typename OutputIt, typename Char, typename AF>
typename basic_printf_context<OutputIt, Char, AF>::format_arg basic_printf_context<OutputIt, Char, AF>::get_arg( typename basic_printf_context<OutputIt, Char, AF>::format_arg
iterator it, unsigned arg_index) basic_printf_context<OutputIt, Char, AF>::get_arg(
{ iterator it, unsigned arg_index) {
(void)it; (void)it;
if (arg_index == std::numeric_limits<unsigned>::max()) if (arg_index == std::numeric_limits<unsigned>::max())
return this->do_get_arg(this->parse_context().next_arg_id()); return this->do_get_arg(this->parse_context().next_arg_id());
return base::get_arg(arg_index - 1); return base::get_arg(arg_index - 1);
} }
template<typename OutputIt, typename Char, typename AF> template <typename OutputIt, typename Char, typename AF>
unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(iterator &it, format_specs &spec) unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
{ iterator &it, format_specs &spec) {
unsigned arg_index = std::numeric_limits<unsigned>::max(); unsigned arg_index = std::numeric_limits<unsigned>::max();
char_type c = *it; char_type c = *it;
if (c >= '0' && c <= '9') if (c >= '0' && c <= '9') {
{ // Parse an argument index (if followed by '$') or a width possibly
// Parse an argument index (if followed by '$') or a width possibly // preceded with '0' flag(s).
// preceded with '0' flag(s). internal::error_handler eh;
internal::error_handler eh; unsigned value = parse_nonnegative_int(it, eh);
unsigned value = parse_nonnegative_int(it, eh); if (*it == '$') { // value is an argument index
if (*it == '$') ++it;
{ // value is an argument index arg_index = value;
++it; } else {
arg_index = value; if (c == '0')
} spec.fill_ = '0';
else if (value != 0) {
{ // Nonzero value means that we parsed width and don't need to
if (c == '0') // parse it or flags again, so return now.
spec.fill_ = '0'; spec.width_ = value;
if (value != 0) return arg_index;
{ }
// Nonzero value means that we parsed width and don't need to }
// parse it or flags again, so return now. }
spec.width_ = value; parse_flags(spec, it);
return arg_index; // Parse width.
} if (*it >= '0' && *it <= '9') {
} internal::error_handler eh;
} spec.width_ = parse_nonnegative_int(it, eh);
parse_flags(spec, it); } else if (*it == '*') {
// Parse width. ++it;
if (*it >= '0' && *it <= '9') spec.width_ =
{ visit(internal::printf_width_handler<char_type>(spec), get_arg(it));
internal::error_handler eh; }
spec.width_ = parse_nonnegative_int(it, eh); return arg_index;
}
else if (*it == '*')
{
++it;
spec.width_ = visit(internal::printf_width_handler<char_type>(spec), get_arg(it));
}
return arg_index;
} }
template<typename OutputIt, typename Char, typename AF> template <typename OutputIt, typename Char, typename AF>
void basic_printf_context<OutputIt, Char, AF>::format() void basic_printf_context<OutputIt, Char, AF>::format() {
{ auto &buffer = internal::get_container(this->out());
auto &buffer = internal::get_container(this->out()); auto start = iterator(this->parse_context());
auto start = iterator(this->parse_context()); auto it = start;
auto it = start; using internal::pointer_from;
using internal::pointer_from; while (*it) {
while (*it) char_type c = *it++;
{ if (c != '%') continue;
char_type c = *it++; if (*it == c) {
if (c != '%') buffer.append(pointer_from(start), pointer_from(it));
continue; start = ++it;
if (*it == c) continue;
{ }
buffer.append(pointer_from(start), pointer_from(it)); buffer.append(pointer_from(start), pointer_from(it) - 1);
start = ++it;
continue; format_specs spec;
} spec.align_ = ALIGN_RIGHT;
buffer.append(pointer_from(start), pointer_from(it) - 1);
// Parse argument index, flags and width.
format_specs spec; unsigned arg_index = parse_header(it, spec);
spec.align_ = ALIGN_RIGHT;
// Parse precision.
// Parse argument index, flags and width. if (*it == '.') {
unsigned arg_index = parse_header(it, spec); ++it;
if ('0' <= *it && *it <= '9') {
// Parse precision. internal::error_handler eh;
if (*it == '.') spec.precision_ = static_cast<int>(parse_nonnegative_int(it, eh));
{ } else if (*it == '*') {
++it; ++it;
if ('0' <= *it && *it <= '9') spec.precision_ =
{ visit(internal::printf_precision_handler(), get_arg(it));
internal::error_handler eh; } else {
spec.precision_ = static_cast<int>(parse_nonnegative_int(it, eh)); spec.precision_ = 0;
} }
else if (*it == '*') }
{
++it; format_arg arg = get_arg(it, arg_index);
spec.precision_ = visit(internal::printf_precision_handler(), get_arg(it)); if (spec.flag(HASH_FLAG) && visit(internal::is_zero_int(), arg))
} spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
else if (spec.fill_ == '0') {
{ if (arg.is_arithmetic())
spec.precision_ = 0; spec.align_ = ALIGN_NUMERIC;
} else
} spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
}
format_arg arg = get_arg(it, arg_index);
if (spec.flag(HASH_FLAG) && visit(internal::is_zero_int(), arg)) // Parse length and convert the argument to the required type.
spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG); using internal::convert_arg;
if (spec.fill_ == '0') switch (*it++) {
{ case 'h':
if (arg.is_arithmetic()) if (*it == 'h')
spec.align_ = ALIGN_NUMERIC; convert_arg<signed char>(arg, *++it);
else else
spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. convert_arg<short>(arg, *it);
} break;
case 'l':
// Parse length and convert the argument to the required type. if (*it == 'l')
using internal::convert_arg; convert_arg<long long>(arg, *++it);
switch (*it++) else
{ convert_arg<long>(arg, *it);
case 'h': break;
if (*it == 'h') case 'j':
convert_arg<signed char>(arg, *++it); convert_arg<intmax_t>(arg, *it);
else break;
convert_arg<short>(arg, *it); case 'z':
break; convert_arg<std::size_t>(arg, *it);
case 'l': break;
if (*it == 'l') case 't':
convert_arg<long long>(arg, *++it); convert_arg<std::ptrdiff_t>(arg, *it);
else break;
convert_arg<long>(arg, *it); case 'L':
break; // printf produces garbage when 'L' is omitted for long double, no
case 'j': // need to do the same.
convert_arg<intmax_t>(arg, *it); break;
break; default:
case 'z': --it;
convert_arg<std::size_t>(arg, *it); convert_arg<void>(arg, *it);
break; }
case 't':
convert_arg<std::ptrdiff_t>(arg, *it); // Parse type.
break; if (!*it)
case 'L': FMT_THROW(format_error("invalid format string"));
// printf produces garbage when 'L' is omitted for long double, no spec.type_ = static_cast<char>(*it++);
// need to do the same. if (arg.is_integral()) {
break; // Normalize type.
default: switch (spec.type_) {
--it; case 'i': case 'u':
convert_arg<void>(arg, *it); spec.type_ = 'd';
} break;
case 'c':
// Parse type. // TODO: handle wchar_t better?
if (!*it) visit(internal::char_converter<basic_printf_context>(arg), arg);
FMT_THROW(format_error("invalid format string")); break;
spec.type_ = static_cast<char>(*it++); }
if (arg.is_integral()) }
{
// Normalize type. start = it;
switch (spec.type_)
{ // Format argument.
case 'i': visit(AF(buffer, spec, *this), arg);
case 'u': }
spec.type_ = 'd'; buffer.append(pointer_from(start), pointer_from(it));
break;
case 'c':
// TODO: handle wchar_t better?
visit(internal::char_converter<basic_printf_context>(arg), arg);
break;
}
}
start = it;
// Format argument.
visit(AF(buffer, spec, *this), arg);
}
buffer.append(pointer_from(start), pointer_from(it));
} }
template<typename Char, typename Context> template <typename Char, typename Context>
void printf(internal::basic_buffer<Char> &buf, basic_string_view<Char> format, basic_format_args<Context> args) void printf(internal::basic_buffer<Char> &buf, basic_string_view<Char> format,
{ basic_format_args<Context> args) {
Context(std::back_inserter(buf), format, args).format(); Context(std::back_inserter(buf), format, args).format();
} }
template<typename Buffer> template <typename Buffer>
struct printf_context struct printf_context {
{ typedef basic_printf_context<
typedef basic_printf_context<std::back_insert_iterator<Buffer>, typename Buffer::value_type> type; std::back_insert_iterator<Buffer>, typename Buffer::value_type> type;
}; };
template<typename... Args> template <typename ...Args>
inline format_arg_store<printf_context<internal::buffer>::type, Args...> make_printf_args(const Args &... args) inline format_arg_store<printf_context<internal::buffer>::type, Args...>
{ make_printf_args(const Args & ... args) {
return format_arg_store<printf_context<internal::buffer>::type, Args...>(args...); return format_arg_store<printf_context<internal::buffer>::type, Args...>(
args...);
} }
typedef basic_format_args<printf_context<internal::buffer>::type> printf_args; typedef basic_format_args<printf_context<internal::buffer>::type> printf_args;
typedef basic_format_args<printf_context<internal::wbuffer>::type> wprintf_args; typedef basic_format_args<printf_context<internal::wbuffer>::type> wprintf_args;
inline std::string vsprintf(string_view format, printf_args args) inline std::string vsprintf(string_view format, printf_args args) {
{ memory_buffer buffer;
memory_buffer buffer; printf(buffer, format, args);
printf(buffer, format, args); return to_string(buffer);
return to_string(buffer);
} }
/** /**
...@@ -661,33 +602,33 @@ inline std::string vsprintf(string_view format, printf_args args) ...@@ -661,33 +602,33 @@ inline std::string vsprintf(string_view format, printf_args args)
std::string message = fmt::sprintf("The answer is %d", 42); std::string message = fmt::sprintf("The answer is %d", 42);
\endrst \endrst
*/ */
template<typename... Args> template <typename... Args>
inline std::string sprintf(string_view format_str, const Args &... args) inline std::string sprintf(string_view format_str, const Args & ... args) {
{ return vsprintf(format_str,
return vsprintf(format_str, make_format_args<typename printf_context<internal::buffer>::type>(args...)); make_format_args<typename printf_context<internal::buffer>::type>(args...));
} }
inline std::wstring vsprintf(wstring_view format, wprintf_args args) inline std::wstring vsprintf(wstring_view format, wprintf_args args) {
{ wmemory_buffer buffer;
wmemory_buffer buffer; printf(buffer, format, args);
printf(buffer, format, args); return to_string(buffer);
return to_string(buffer);
} }
template<typename... Args> template <typename... Args>
inline std::wstring sprintf(wstring_view format_str, const Args &... args) inline std::wstring sprintf(wstring_view format_str, const Args & ... args) {
{ return vsprintf(format_str,
return vsprintf(format_str, make_format_args<typename printf_context<internal::wbuffer>::type>(args...)); make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
} }
template<typename Char> template <typename Char>
inline int vfprintf( inline int vfprintf(std::FILE *f, basic_string_view<Char> format,
std::FILE *f, basic_string_view<Char> format, basic_format_args<typename printf_context<internal::basic_buffer<Char>>::type> args) basic_format_args<typename printf_context<
{ internal::basic_buffer<Char>>::type> args) {
basic_memory_buffer<Char> buffer; basic_memory_buffer<Char> buffer;
printf(buffer, format, args); printf(buffer, format, args);
std::size_t size = buffer.size(); std::size_t size = buffer.size();
return std::fwrite(buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size); return std::fwrite(
buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size);
} }
/** /**
...@@ -699,27 +640,26 @@ inline int vfprintf( ...@@ -699,27 +640,26 @@ inline int vfprintf(
fmt::fprintf(stderr, "Don't %s!", "panic"); fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst \endrst
*/ */
template<typename... Args> template <typename... Args>
inline int fprintf(std::FILE *f, string_view format_str, const Args &... args) inline int fprintf(std::FILE *f, string_view format_str, const Args & ... args) {
{ auto vargs = make_format_args<
auto vargs = make_format_args<typename printf_context<internal::buffer>::type>(args...); typename printf_context<internal::buffer>::type>(args...);
return vfprintf<char>(f, format_str, vargs); return vfprintf<char>(f, format_str, vargs);
} }
template<typename... Args> template <typename... Args>
inline int fprintf(std::FILE *f, wstring_view format_str, const Args &... args) inline int fprintf(std::FILE *f, wstring_view format_str,
{ const Args & ... args) {
return vfprintf(f, format_str, make_format_args<typename printf_context<internal::wbuffer>::type>(args...)); return vfprintf(f, format_str,
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
} }
inline int vprintf(string_view format, printf_args args) inline int vprintf(string_view format, printf_args args) {
{ return vfprintf(stdout, format, args);
return vfprintf(stdout, format, args);
} }
inline int vprintf(wstring_view format, wprintf_args args) inline int vprintf(wstring_view format, wprintf_args args) {
{ return vfprintf(stdout, format, args);
return vfprintf(stdout, format, args);
} }
/** /**
...@@ -731,32 +671,32 @@ inline int vprintf(wstring_view format, wprintf_args args) ...@@ -731,32 +671,32 @@ inline int vprintf(wstring_view format, wprintf_args args)
fmt::printf("Elapsed time: %.2f seconds", 1.23); fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst \endrst
*/ */
template<typename... Args> template <typename... Args>
inline int printf(string_view format_str, const Args &... args) inline int printf(string_view format_str, const Args & ... args) {
{ return vprintf(format_str,
return vprintf(format_str, make_format_args<typename printf_context<internal::buffer>::type>(args...)); make_format_args<typename printf_context<internal::buffer>::type>(args...));
} }
template<typename... Args> template <typename... Args>
inline int printf(wstring_view format_str, const Args &... args) inline int printf(wstring_view format_str, const Args & ... args) {
{ return vprintf(format_str,
return vprintf(format_str, make_format_args<typename printf_context<internal::wbuffer>::type>(args...)); make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
} }
inline int vfprintf(std::ostream &os, string_view format_str, printf_args args) inline int vfprintf(std::ostream &os, string_view format_str,
{ printf_args args) {
memory_buffer buffer; memory_buffer buffer;
printf(buffer, format_str, args); printf(buffer, format_str, args);
internal::write(os, buffer); internal::write(os, buffer);
return static_cast<int>(buffer.size()); return static_cast<int>(buffer.size());
} }
inline int vfprintf(std::wostream &os, wstring_view format_str, wprintf_args args) inline int vfprintf(std::wostream &os, wstring_view format_str,
{ wprintf_args args) {
wmemory_buffer buffer; wmemory_buffer buffer;
printf(buffer, format_str, args); printf(buffer, format_str, args);
internal::write(os, buffer); internal::write(os, buffer);
return static_cast<int>(buffer.size()); return static_cast<int>(buffer.size());
} }
/** /**
...@@ -768,19 +708,21 @@ inline int vfprintf(std::wostream &os, wstring_view format_str, wprintf_args arg ...@@ -768,19 +708,21 @@ inline int vfprintf(std::wostream &os, wstring_view format_str, wprintf_args arg
fmt::fprintf(cerr, "Don't %s!", "panic"); fmt::fprintf(cerr, "Don't %s!", "panic");
\endrst \endrst
*/ */
template<typename... Args> template <typename... Args>
inline int fprintf(std::ostream &os, string_view format_str, const Args &... args) inline int fprintf(std::ostream &os, string_view format_str,
{ const Args & ... args) {
auto vargs = make_format_args<typename printf_context<internal::buffer>::type>(args...); auto vargs = make_format_args<
return vfprintf(os, format_str, vargs); typename printf_context<internal::buffer>::type>(args...);
return vfprintf(os, format_str, vargs);
} }
template<typename... Args> template <typename... Args>
inline int fprintf(std::wostream &os, wstring_view format_str, const Args &... args) inline int fprintf(std::wostream &os, wstring_view format_str,
{ const Args & ... args) {
auto vargs = make_format_args<typename printf_context<internal::buffer>::type>(args...); auto vargs = make_format_args<
return vfprintf(os, format_str, vargs); typename printf_context<internal::buffer>::type>(args...);
return vfprintf(os, format_str, vargs);
} }
FMT_END_NAMESPACE FMT_END_NAMESPACE
#endif // FMT_PRINTF_H_ #endif // FMT_PRINTF_H_
...@@ -17,326 +17,289 @@ ...@@ -17,326 +17,289 @@
// 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
#define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256 # define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256
#endif #endif
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();
}
}; };
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; formatting_range() : prefix('{'), delimiter(','), postfix('}') {}
formatting_range() static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
: prefix('{') static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
, delimiter(',')
, postfix('}')
{
}
static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
}; };
template<typename Char, typename Enable = void> template <typename Char, typename Enable = void>
struct formatting_tuple : formatting_base<Char> struct formatting_tuple : formatting_base<Char> {
{ Char prefix;
Char prefix; Char delimiter;
Char delimiter; Char postfix;
Char postfix; formatting_tuple() : prefix('('), delimiter(','), postfix(')') {}
formatting_tuple() static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
: prefix('(') static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
, delimiter(',')
, postfix(')')
{
}
static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
}; };
namespace internal { namespace internal {
template<typename RangeT, typename OutputIterator> template <typename RangeT, typename OutputIterator>
void copy(const RangeT &range, OutputIterator out) void 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;
} }
template<typename OutputIterator> template <typename OutputIterator>
void copy(const char *str, OutputIterator out) void copy(const char *str, OutputIterator out) {
{ const char *p_curr = str;
const char *p_curr = str; while (*p_curr) {
while (*p_curr) *out++ = *p_curr++;
{ }
*out++ = *p_curr++;
}
} }
template<typename OutputIterator> template <typename OutputIterator>
void copy(char ch, OutputIterator out) void copy(char ch, OutputIterator out) {
{ *out++ = ch;
*out++ = ch;
} }
/// 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(p->find('a'), p->length(), p->data(), int());
template<typename> template <typename>
static void check(...); static void check(...);
public: public:
static FMT_CONSTEXPR_DECL const bool value = !std::is_void<decltype(check<T>(FMT_NULL))>::value; static FMT_CONSTEXPR_DECL const bool value =
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
}; };
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 {};
{
};
template<typename T> #if !FMT_MSC_VER || FMT_MSC_VER > 1800
struct is_range_<T, typename std::conditional<false, template <typename T>
conditional_helper<decltype(internal::declval<T>().begin()), decltype(internal::declval<T>().end())>, void>::type> struct is_range_<T, typename std::conditional<
: std::true_type false,
{ conditional_helper<decltype(internal::declval<T>().begin()),
}; decltype(internal::declval<T>().end())>,
void>::type> : std::true_type {};
#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, internal::declval<typename std::tuple_element<0, U>::type>(), int()); decltype(std::tuple_size<U>::value,
template<typename> internal::declval<typename std::tuple_element<0, U>::type>(), int());
static void check(...); template <typename>
static void check(...);
public:
static FMT_CONSTEXPR_DECL const bool value = !std::is_void<decltype(check<T>(FMT_NULL))>::value; public:
static FMT_CONSTEXPR_DECL const bool value =
!std::is_void<decltype(check<T>(FMT_NULL))>::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 {
{ typedef T value_type;
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>
using index_sequence = integer_sequence<std::size_t, N...>; using index_sequence = integer_sequence<std::size_t, N...>;
template<typename T, std::size_t N, T... Ns> template <typename T, std::size_t N, T... Ns>
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
{ template <typename T, T... Ns>
}; struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
template<typename T, T... Ns>
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...>
{
};
template<std::size_t N> template <std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>; 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) 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)...}; (void)_; // blocks warnings
(void)_; // blocks warnings
} }
template<class T> template <class T>
FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes(T const &) FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value>
{ get_indexes(T const &) { return {}; }
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_CONSTEXPR const char *format_str_quoted( FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&,
bool add_space, const Arg &, typename std::enable_if<!is_like_std_string<typename std::decay<Arg>::type>::value>::type * = nullptr) typename std::enable_if<
{ !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_CONSTEXPR const char *format_str_quoted( FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&,
bool add_space, const Arg &, typename std::enable_if<is_like_std_string<typename std::decay<Arg>::type>::value>::type * = nullptr) typename std::enable_if<
{ is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
return add_space ? " \"{}\"" : "\"{}\""; return add_space ? " \"{}\"" : "\"{}\"";
} }
FMT_CONSTEXPR const char *format_str_quoted(bool add_space, const char *) FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char*) {
{ return add_space ? " \"{}\"" : "\"{}\"";
return add_space ? " \"{}\"" : "\"{}\"";
} }
FMT_CONSTEXPR const wchar_t *format_str_quoted(bool add_space, const wchar_t *) FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) {
{
return add_space ? L" \"{}\"" : L"\"{}\""; return add_space ? L" \"{}\"" : L"\"{}\"";
} }
FMT_CONSTEXPR const char *format_str_quoted(bool add_space, const char) FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) {
{
return add_space ? " '{}'" : "'{}'"; return add_space ? " '{}'" : "'{}'";
} }
FMT_CONSTEXPR const wchar_t *format_str_quoted(bool add_space, const wchar_t) FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
{
return add_space ? L" '{}'" : L"'{}'"; return add_space ? L" '{}'" : L"'{}'";
} }
} // 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, typename std::enable_if<fmt::is_tuple_like<TupleT>::value>::type> struct formatter<TupleT, Char,
{ 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>
template<typename T> void operator()(const T& v) {
void operator()(const T &v) if (i > 0) {
{ if (formatting.add_prepostfix_space) {
if (i > 0) *out++ = ' ';
{
if (formatting.add_prepostfix_space)
{
*out++ = ' ';
}
internal::copy(formatting.delimiter, out);
}
format_to(out, internal::format_str_quoted((formatting.add_delimiter_spaces && i > 0), v), v);
++i;
} }
internal::copy(formatting.delimiter, out);
}
format_to(out,
internal::format_str_quoted(
(formatting.add_delimiter_spaces && i > 0), v),
v);
++i;
}
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>
auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) {
auto out = ctx.out();
std::size_t i = 0;
internal::copy(formatting.prefix, out);
internal::for_each(values, format_each<FormatContext>{formatting, i, out});
if (formatting.add_prepostfix_space) {
*out++ = ' ';
} }
internal::copy(formatting.postfix, out);
template<typename FormatContext = format_context> return ctx.out();
auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) }
{
auto out = ctx.out();
std::size_t i = 0;
internal::copy(formatting.prefix, out);
internal::for_each(values, format_each<FormatContext>{formatting, i, out});
if (formatting.add_prepostfix_space)
{
*out++ = ' ';
}
internal::copy(formatting.postfix, out);
return ctx.out();
}
}; };
template<typename T> template <typename T>
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;
}; };
template<typename RangeT, typename Char> template <typename RangeT, typename Char>
struct formatter<RangeT, Char, typename std::enable_if<fmt::is_range<RangeT>::value>::type> struct formatter<RangeT, Char,
{ typename std::enable_if<fmt::is_range<RangeT>::value>::type> {
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, FormatContext &ctx) const RangeT &values, FormatContext &ctx) {
{ auto out = ctx.out();
auto out = ctx.out(); internal::copy(formatting.prefix, 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 (formatting.add_prepostfix_space) {
if (i > 0) *out++ = ' ';
{
if (formatting.add_prepostfix_space)
{
*out++ = ' ';
}
internal::copy(formatting.delimiter, out);
}
format_to(out, internal::format_str_quoted((formatting.add_delimiter_spaces && i > 0), *it), *it);
if (++i > formatting.range_length_limit)
{
format_to(out, " ... <other elements>");
break;
}
} }
if (formatting.add_prepostfix_space) internal::copy(formatting.delimiter, out);
{ }
*out++ = ' '; format_to(out,
} internal::format_str_quoted(
internal::copy(formatting.postfix, out); (formatting.add_delimiter_spaces && i > 0), *it),
return ctx.out(); *it);
if (++i > formatting.range_length_limit) {
format_to(out, " ... <other elements>");
break;
}
}
if (formatting.add_prepostfix_space) {
*out++ = ' ';
} }
internal::copy(formatting.postfix, out);
return ctx.out();
}
}; };
FMT_END_NAMESPACE FMT_END_NAMESPACE
#endif // FMT_RANGES_H_ #endif // FMT_RANGES_H_
...@@ -13,187 +13,140 @@ ...@@ -13,187 +13,140 @@
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
namespace internal { namespace internal{
inline null<> localtime_r(...) inline null<> localtime_r(...) { return null<>(); }
{ inline null<> localtime_s(...) { return null<>(); }
return null<>(); inline null<> gmtime_r(...) { return null<>(); }
} inline null<> gmtime_s(...) { 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 // Thread-safe replacement for std::localtime
inline std::tm localtime(std::time_t time) inline std::tm localtime(std::time_t time) {
{ struct dispatcher {
struct dispatcher std::time_t time_;
{ std::tm tm_;
std::time_t time_;
std::tm tm_; dispatcher(std::time_t t): time_(t) {}
dispatcher(std::time_t t) bool run() {
: time_(t) using namespace fmt::internal;
{ return handle(localtime_r(&time_, &tm_));
} }
bool run() bool handle(std::tm *tm) { return tm != FMT_NULL; }
{
using namespace fmt::internal; bool handle(internal::null<>) {
return handle(localtime_r(&time_, &tm_)); using namespace fmt::internal;
} return fallback(localtime_s(&tm_, &time_));
}
bool handle(std::tm *tm)
{ bool fallback(int res) { return res == 0; }
return tm != FMT_NULL;
} bool fallback(internal::null<>) {
using namespace fmt::internal;
bool handle(internal::null<>) std::tm *tm = std::localtime(&time_);
{ if (tm) tm_ = *tm;
using namespace fmt::internal; return tm != FMT_NULL;
return fallback(localtime_s(&tm_, &time_)); }
} };
dispatcher lt(time);
bool fallback(int res) if (lt.run())
{ return lt.tm_;
return res == 0; // Too big time values may be unsupported.
} FMT_THROW(format_error("time_t value out of range"));
bool fallback(internal::null<>)
{
using namespace fmt::internal;
std::tm *tm = std::localtime(&time_);
if (tm)
tm_ = *tm;
return tm != FMT_NULL;
}
};
dispatcher lt(time);
if (lt.run())
return lt.tm_;
// Too big time values may be unsupported.
FMT_THROW(format_error("time_t value out of range"));
} }
// Thread-safe replacement for std::gmtime // Thread-safe replacement for std::gmtime
inline std::tm gmtime(std::time_t time) inline std::tm gmtime(std::time_t time) {
{ struct dispatcher {
struct dispatcher std::time_t time_;
{ std::tm tm_;
std::time_t time_;
std::tm tm_; dispatcher(std::time_t t): time_(t) {}
dispatcher(std::time_t t) bool run() {
: time_(t) using namespace fmt::internal;
{ return handle(gmtime_r(&time_, &tm_));
} }
bool run() bool handle(std::tm *tm) { return tm != FMT_NULL; }
{
using namespace fmt::internal; bool handle(internal::null<>) {
return handle(gmtime_r(&time_, &tm_)); using namespace fmt::internal;
} return fallback(gmtime_s(&tm_, &time_));
}
bool handle(std::tm *tm)
{ bool fallback(int res) { return res == 0; }
return tm != FMT_NULL;
} bool fallback(internal::null<>) {
std::tm *tm = std::gmtime(&time_);
bool handle(internal::null<>) if (tm) tm_ = *tm;
{ return tm != FMT_NULL;
using namespace fmt::internal; }
return fallback(gmtime_s(&tm_, &time_)); };
} dispatcher gt(time);
if (gt.run())
bool fallback(int res) return gt.tm_;
{ // Too big time values may be unsupported.
return res == 0; FMT_THROW(format_error("time_t value out of range"));
}
bool fallback(internal::null<>)
{
std::tm *tm = std::gmtime(&time_);
if (tm)
tm_ = *tm;
return tm != FMT_NULL;
}
};
dispatcher gt(time);
if (gt.run())
return gt.tm_;
// Too big time values may be unsupported.
FMT_THROW(format_error("time_t value out of range"));
} }
namespace internal { namespace internal {
inline std::size_t strftime(char *str, std::size_t count, const char *format, const std::tm *time) 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); 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) 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); 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 = internal::null_terminating_iterator<Char>(ctx);
if (*it == ':')
++it;
auto end = it;
while (*end && *end != '}')
++end;
tm_format.reserve(end - it + 1);
using internal::pointer_from;
tm_format.append(pointer_from(it), pointer_from(end));
tm_format.push_back('\0');
return pointer_from(end);
}
template<typename FormatContext> template <typename Char>
auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) struct formatter<std::tm, Char> {
{ template <typename ParseContext>
internal::basic_buffer<Char> &buf = internal::get_container(ctx.out()); auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
std::size_t start = buf.size(); auto it = internal::null_terminating_iterator<Char>(ctx);
for (;;) if (*it == ':')
{ ++it;
std::size_t size = buf.capacity() - start; auto end = it;
std::size_t count = internal::strftime(&buf[start], size, &tm_format[0], &tm); while (*end && *end != '}')
if (count != 0) ++end;
{ tm_format.reserve(end - it + 1);
buf.resize(start + count); using internal::pointer_from;
break; tm_format.append(pointer_from(it), pointer_from(end));
} tm_format.push_back('\0');
if (size >= tm_format.size() * 256) return pointer_from(end);
{ }
// 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 template <typename FormatContext>
// better way to distinguish the two cases: auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) {
// https://github.com/fmtlib/fmt/issues/367 internal::basic_buffer<Char> &buf = internal::get_container(ctx.out());
break; std::size_t start = buf.size();
} for (;;) {
const std::size_t MIN_GROWTH = 10; std::size_t size = buf.capacity() - start;
buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); std::size_t count =
} internal::strftime(&buf[start], size, &tm_format[0], &tm);
return ctx.out(); 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 ctx.out();
}
basic_memory_buffer<Char> tm_format; basic_memory_buffer<Char> tm_format;
}; };
FMT_END_NAMESPACE FMT_END_NAMESPACE
#endif // FMT_TIME_H_ #endif // FMT_TIME_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment