Commit 06e0b038 authored by gabime's avatar gabime

Merge branch 'master' of https://github.com/gabime/spdlog

parents 285a47de 80fcd655
/*
Formatting library for C++
Copyright (c) 2012 - 2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
Formatting library for C++
Copyright (c) 2012 - 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "format.h"
......@@ -66,10 +66,8 @@ using fmt::internal::Arg;
#ifndef FMT_THROW
# if FMT_EXCEPTIONS
# define FMT_THROW(x) throw x
# define FMT_RETURN_AFTER_THROW(x)
# else
# define FMT_THROW(x) assert(false)
# define FMT_RETURN_AFTER_THROW(x) return x
# endif
#endif
......@@ -83,8 +81,20 @@ using fmt::internal::Arg;
# pragma warning(push)
# pragma warning(disable: 4127) // conditional expression is constant
# pragma warning(disable: 4702) // unreachable code
// Disable deprecation warning for strerror. The latter is not called but
// MSVC fails to detect it.
# pragma warning(disable: 4996)
#endif
// Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available.
static inline fmt::internal::None<> strerror_r(int, char *, ...) {
return fmt::internal::None<>();
}
static inline fmt::internal::None<> strerror_s(char *, std::size_t, ...) {
return fmt::internal::None<>();
}
namespace {
#ifndef _MSC_VER
......@@ -100,6 +110,12 @@ inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
# define FMT_SNPRINTF fmt_snprintf
#endif // _MSC_VER
#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
# define FMT_SWPRINTF snwprintf
#else
# define FMT_SWPRINTF swprintf
#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
template <bool IsSigned>
......@@ -121,7 +137,7 @@ struct IntChecker<true> {
const char RESET_COLOR[] = "\x1b[0m";
typedef void(*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
// Portable thread-safe version of strerror.
// Sets buffer to point to a string describing the error code.
......@@ -133,59 +149,81 @@ typedef void(*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
// other - failure
// Buffer should be at least of size 1.
int safe_strerror(
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT{
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
assert(buffer != 0 && buffer_size != 0);
int result = 0;
#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || __ANDROID__
// XSI-compliant version of strerror_r.
result = strerror_r(error_code, buffer, buffer_size);
if (result != 0)
result = errno;
#elif _GNU_SOURCE
// GNU-specific version of strerror_r.
char *message = strerror_r(error_code, buffer, buffer_size);
class StrError {
private:
int error_code_;
char *&buffer_;
std::size_t buffer_size_;
// A noop assignment operator to avoid bogus warnings.
void operator=(const StrError &) {}
// Handle the result of XSI-compliant version of strerror_r.
int handle(int 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.
int handle(char *message) {
// If the buffer is full then the message is probably truncated.
if (message == buffer && strlen(buffer) == buffer_size - 1)
result = ERANGE;
buffer = message;
#elif __MINGW32__
errno = 0;
(void)buffer_size;
buffer = strerror(error_code);
result = errno;
#elif _WIN32
result = strerror_s(buffer, buffer_size, error_code);
if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
return ERANGE;
buffer_ = message;
return 0;
}
// Handle the case when strerror_r is not available.
int handle(fmt::internal::None<>) {
return fallback(strerror_s(buffer_, buffer_size_, error_code_));
}
// Fallback to strerror_s when strerror_r is not available.
int fallback(int result) {
// If the buffer is full then the message is probably truncated.
if (result == 0 && std::strlen(buffer) == buffer_size - 1)
result = ERANGE;
#else
result = strerror_r(error_code, buffer, buffer_size);
if (result == -1)
result = errno; // glibc versions before 2.13 return result in errno.
#endif
return result;
return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
ERANGE : result;
}
// Fallback to strerror if strerror_r and strerror_s are not available.
int fallback(fmt::internal::None<>) {
errno = 0;
buffer_ = strerror(error_code_);
return errno;
}
public:
StrError(int error_code, char *&buffer, std::size_t buffer_size)
: error_code_(error_code), buffer_(buffer), buffer_size_(buffer_size) {}
int run() { return handle(strerror_r(error_code_, buffer_, buffer_size_)); }
};
return StrError(error_code, buffer, buffer_size).run();
}
void format_error_code(fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT{
fmt::StringRef message) FMT_NOEXCEPT {
// Report error code making sure that the output fits into
// INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
// bad_alloc.
out.clear();
static const char SEP[] = ": ";
static const char ERR[] = "error ";
static const char ERROR_STR[] = "error ";
fmt::internal::IntTraits<int>::MainType ec_value = error_code;
// Subtract 2 to account for terminating null characters in SEP and ERR.
std::size_t error_code_size =
sizeof(SEP) + sizeof(ERR) + fmt::internal::count_digits(ec_value) - 2;
// 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;
error_code_size += fmt::internal::count_digits(ec_value);
if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
out << message << SEP;
out << ERR << error_code;
out << ERROR_STR << error_code;
assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
}
void report_error(FormatFunc func,
int error_code, fmt::StringRef message) FMT_NOEXCEPT{
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
fmt::MemoryWriter full_message;
func(full_message, error_code, message);
// Use Writer::data instead of Writer::c_str to avoid potential memory
......@@ -196,11 +234,9 @@ void report_error(FormatFunc func,
// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
public:
public:
template <typename T>
bool visit_any_int(T value) {
return value == 0;
}
bool visit_any_int(T value) { return value == 0; }
};
// Parses an unsigned integer advancing s to the end of the parsed input.
......@@ -245,17 +281,16 @@ void check_sign(const Char *&s, const Arg &arg) {
// Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative.
class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
private:
private:
fmt::FormatSpec &spec_;
FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
public:
public:
explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
unsigned visit_unhandled_arg() {
void report_unhandled_arg() {
FMT_THROW(fmt::FormatError("width is not integer"));
FMT_RETURN_AFTER_THROW(0);
}
template <typename T>
......@@ -274,10 +309,9 @@ public:
class PrecisionHandler :
public fmt::internal::ArgVisitor<PrecisionHandler, int> {
public:
unsigned visit_unhandled_arg() {
public:
void report_unhandled_arg() {
FMT_THROW(fmt::FormatError("precision is not integer"));
FMT_RETURN_AFTER_THROW(0);
}
template <typename T>
......@@ -291,13 +325,13 @@ public:
// Converts an integer argument to an integral type T for printf.
template <typename T>
class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
private:
private:
fmt::internal::Arg &arg_;
wchar_t type_;
FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
public:
public:
ArgConverter(fmt::internal::Arg &arg, wchar_t type)
: arg_(arg), type_(type) {}
......@@ -310,20 +344,17 @@ public:
if (is_signed) {
arg_.type = Arg::INT;
arg_.int_value = static_cast<int>(static_cast<T>(value));
}
else {
} else {
arg_.type = Arg::UINT;
arg_.uint_value = static_cast<unsigned>(
static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
}
}
else {
} else {
if (is_signed) {
arg_.type = Arg::LONG_LONG;
arg_.long_long_value =
static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
}
else {
} else {
arg_.type = Arg::ULONG_LONG;
arg_.ulong_long_value =
static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
......@@ -334,12 +365,12 @@ public:
// Converts an integer argument to char for printf.
class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
private:
private:
fmt::internal::Arg &arg_;
FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
public:
public:
explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
template <typename T>
......@@ -357,15 +388,11 @@ Arg::StringValue<Char> ignore_incompatible_str(Arg::StringValue<wchar_t>);
template <>
inline Arg::StringValue<char> ignore_incompatible_str(
Arg::StringValue<wchar_t>) {
return Arg::StringValue<char>();
}
Arg::StringValue<wchar_t>) { return Arg::StringValue<char>(); }
template <>
inline Arg::StringValue<wchar_t> ignore_incompatible_str(
Arg::StringValue<wchar_t> s) {
return s;
}
Arg::StringValue<wchar_t> s) { return s; }
} // namespace
FMT_FUNC void fmt::SystemError::init(
......@@ -397,12 +424,12 @@ int fmt::internal::CharTraits<wchar_t>::format_float(
unsigned width, int precision, T value) {
if (width == 0) {
return precision < 0 ?
swprintf(buffer, size, format, value) :
swprintf(buffer, size, format, precision, value);
FMT_SWPRINTF(buffer, size, format, value) :
FMT_SWPRINTF(buffer, size, format, precision, value);
}
return precision < 0 ?
swprintf(buffer, size, format, width, value) :
swprintf(buffer, size, format, width, precision, value);
FMT_SWPRINTF(buffer, size, format, width, value) :
FMT_SWPRINTF(buffer, size, format, width, precision, value);
}
template <typename T>
......@@ -440,6 +467,7 @@ const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
};
FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
(void)type;
if (std::isprint(static_cast<unsigned char>(code))) {
FMT_THROW(fmt::FormatError(
fmt::format("unknown format code '{}' for {}", code, type)));
......@@ -496,8 +524,8 @@ FMT_FUNC void fmt::WindowsError::init(
FMT_FUNC void fmt::internal::format_system_error(
fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT{
FMT_TRY{
fmt::StringRef message) FMT_NOEXCEPT {
FMT_TRY {
MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
buffer.resize(INLINE_BUFFER_SIZE);
for (;;) {
......@@ -518,22 +546,18 @@ FMT_FUNC void fmt::internal::format_system_error(
#ifdef _WIN32
FMT_FUNC void fmt::internal::format_windows_error(
fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT{
fmt::StringRef message) FMT_NOEXCEPT {
class String {
private:
LPWSTR str_;
public:
String() : str_() {}
~String() {
LocalFree(str_);
}
LPWSTR *ptr() {
return &str_;
}
~String() { LocalFree(str_); }
LPWSTR *ptr() { return &str_; }
LPCWSTR c_str() const { return str_; }
};
FMT_TRY{
FMT_TRY {
String system_message;
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
......@@ -554,7 +578,7 @@ FMT_FUNC void fmt::internal::format_windows_error(
template <typename Char>
class fmt::internal::ArgFormatter :
public fmt::internal::ArgVisitor<fmt::internal::ArgFormatter<Char>, void> {
private:
private:
fmt::BasicFormatter<Char> &formatter_;
fmt::BasicWriter<Char> &writer_;
fmt::FormatSpec &spec_;
......@@ -562,20 +586,16 @@ private:
FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatter);
public:
public:
ArgFormatter(
fmt::BasicFormatter<Char> &f, fmt::FormatSpec &s, const Char *fmt)
fmt::BasicFormatter<Char> &f,fmt::FormatSpec &s, const Char *fmt)
: formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {}
template <typename T>
void visit_any_int(T value) {
writer_.write_int(value, spec_);
}
void visit_any_int(T value) { writer_.write_int(value, spec_); }
template <typename T>
void visit_any_double(T value) {
writer_.write_double(value, spec_);
}
void visit_any_double(T value) { writer_.write_double(value, spec_); }
void visit_char(int value) {
if (spec_.type_ && spec_.type_ != 'c') {
......@@ -597,15 +617,12 @@ public:
if (spec_.align_ == fmt::ALIGN_RIGHT) {
std::fill_n(out, spec_.width_ - 1, fill);
out += spec_.width_ - 1;
}
else if (spec_.align_ == fmt::ALIGN_CENTER) {
} else if (spec_.align_ == fmt::ALIGN_CENTER) {
out = writer_.fill_padding(out, spec_.width_, 1, fill);
}
else {
} else {
std::fill_n(out + 1, spec_.width_ - 1, fill);
}
}
else {
} else {
out = writer_.grow_buffer(1);
}
*out = static_cast<Char>(value);
......@@ -631,6 +648,11 @@ public:
}
};
template <typename Char>
void fmt::internal::FixedBuffer<Char>::grow(std::size_t) {
FMT_THROW(std::runtime_error("buffer overflow"));
}
template <typename Char>
template <typename StrChar>
void fmt::BasicWriter<Char>::write_str(
......@@ -720,6 +742,7 @@ void fmt::internal::PrintfFormatter<Char>::parse_flags(
template <typename Char>
Arg fmt::internal::PrintfFormatter<Char>::get_arg(
const Char *s, unsigned arg_index) {
(void)s;
const char *error = 0;
Arg arg = arg_index == UINT_MAX ?
next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
......@@ -740,8 +763,7 @@ unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
if (*s == '$') { // value is an argument index
++s;
arg_index = value;
}
else {
} else {
if (c == '0')
spec.fill_ = '0';
if (value != 0) {
......@@ -756,8 +778,7 @@ unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
// Parse width.
if (*s >= '0' && *s <= '9') {
spec.width_ = parse_nonnegative_int(s);
}
else if (*s == '*') {
} else if (*s == '*') {
++s;
spec.width_ = WidthHandler(spec).visit(get_arg(s));
}
......@@ -792,8 +813,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
++s;
if ('0' <= *s && *s <= '9') {
spec.precision_ = parse_nonnegative_int(s);
}
else if (*s == '*') {
} else if (*s == '*') {
++s;
spec.precision_ = PrecisionHandler().visit(get_arg(s));
}
......@@ -848,8 +868,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
if (arg.type <= Arg::LAST_INTEGER_TYPE) {
// Normalize type.
switch (spec.type_) {
case 'i':
case 'u':
case 'i': case 'u':
spec.type_ = 'd';
break;
case 'c':
......@@ -886,12 +905,10 @@ void fmt::internal::PrintfFormatter<Char>::format(
if (spec.align_ != ALIGN_LEFT) {
std::fill_n(out, spec.width_ - 1, fill);
out += spec.width_ - 1;
}
else {
} else {
std::fill_n(out + 1, spec.width_ - 1, fill);
}
}
else {
} else {
out = writer.grow_buffer(1);
}
*out = static_cast<Char>(arg.int_value);
......@@ -916,7 +933,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
case Arg::POINTER:
if (spec.type_ && spec.type_ != 'p')
internal::report_unknown_type(spec.type_, "pointer");
spec.flags_ = HASH_FLAG;
spec.flags_= HASH_FLAG;
spec.type_ = 'x';
writer.write_int(reinterpret_cast<uintptr_t>(arg.pointer), spec);
break;
......@@ -972,8 +989,7 @@ const Char *fmt::BasicFormatter<Char>::format(
FMT_THROW(FormatError("invalid fill character '{'"));
s += 2;
spec.fill_ = c;
}
else ++s;
} else ++s;
if (spec.align_ == ALIGN_NUMERIC)
require_numeric_argument(arg, '=');
break;
......@@ -1021,8 +1037,7 @@ const Char *fmt::BasicFormatter<Char>::format(
spec.precision_ = 0;
if ('0' <= *s && *s <= '9') {
spec.precision_ = parse_nonnegative_int(s);
}
else if (*s == '{') {
} else if (*s == '{') {
++s;
const Arg &precision_arg = parse_arg_index(s);
if (*s++ != '}')
......@@ -1051,8 +1066,7 @@ const Char *fmt::BasicFormatter<Char>::format(
if (value > INT_MAX)
FMT_THROW(FormatError("number is too big"));
spec.precision_ = static_cast<int>(value);
}
else {
} else {
FMT_THROW(FormatError("missing precision specifier"));
}
if (arg.type < Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) {
......@@ -1099,13 +1113,13 @@ void fmt::BasicFormatter<Char>::format(
}
FMT_FUNC void fmt::report_system_error(
int error_code, fmt::StringRef message) FMT_NOEXCEPT{
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
report_error(internal::format_system_error, error_code, message);
}
#ifdef _WIN32
FMT_FUNC void fmt::report_windows_error(
int error_code, fmt::StringRef message) FMT_NOEXCEPT{
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
report_error(internal::format_windows_error, error_code, message);
}
#endif
......@@ -1141,8 +1155,12 @@ FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
}
#ifndef FMT_HEADER_ONLY
// Explicit instantiations for char.
template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
template const char *fmt::BasicFormatter<char>::format(
const char *&format_str, const fmt::internal::Arg &arg);
......@@ -1162,6 +1180,8 @@ template int fmt::internal::CharTraits<char>::format_float(
// Explicit instantiations for wchar_t.
template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t);
template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
const wchar_t *&format_str, const fmt::internal::Arg &arg);
......@@ -1180,6 +1200,8 @@ template int fmt::internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, long double value);
#endif // FMT_HEADER_ONLY
#if _MSC_VER
# pragma warning(pop)
#endif
\ No newline at end of file
/*
Formatting library for C++
Copyright (c) 2012 - 2014, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
Formatting library for C++
Copyright (c) 2012 - 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FMT_FORMAT_H_
#define FMT_FORMAT_H_
......@@ -49,13 +49,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef _MSC_VER
# include <intrin.h> // _BitScanReverse, _BitScanReverse64
namespace fmt
{
namespace internal
{
namespace fmt {
namespace internal {
# pragma intrinsic(_BitScanReverse)
inline uint32_t clz(uint32_t x)
{
inline uint32_t clz(uint32_t x) {
unsigned long r = 0;
_BitScanReverse(&r, x);
return 31 - r;
......@@ -66,8 +63,7 @@ inline uint32_t clz(uint32_t x)
# pragma intrinsic(_BitScanReverse64)
# endif
inline uint32_t clzll(uint64_t x)
{
inline uint32_t clzll(uint64_t x) {
unsigned long r = 0;
# ifdef _WIN64
_BitScanReverse64(&r, x);
......@@ -178,8 +174,7 @@ inline uint32_t clzll(uint64_t x)
TypeName& operator=(const TypeName&)
#endif
namespace fmt
{
namespace fmt {
// Fix the warning about long long on older versions of GCC
// that don't support the diagnostic pragma.
......@@ -203,38 +198,37 @@ template <typename Char, typename T>
void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value);
/**
\rst
A string reference. It can be constructed from a C string or
``std::string``.
\rst
A string reference. It can be constructed from a C string or
``std::string``.
You can use one of the following typedefs for common character types:
You can use one of the following typedefs for common character types:
+------------+-------------------------+
| Type | Definition |
+============+=========================+
| StringRef | BasicStringRef<char> |
+------------+-------------------------+
| WStringRef | BasicStringRef<wchar_t> |
+------------+-------------------------+
+------------+-------------------------+
| Type | Definition |
+============+=========================+
| StringRef | BasicStringRef<char> |
+------------+-------------------------+
| WStringRef | BasicStringRef<wchar_t> |
+------------+-------------------------+
This class is most useful as a parameter type to allow passing
different types of strings to a function, for example::
This class is most useful as a parameter type to allow passing
different types of strings to a function, for example::
template <typename... Args>
std::string format(StringRef format_str, const Args & ... args);
template <typename... Args>
std::string format(StringRef format_str, const Args & ... args);
format("{}", 42);
format(std::string("{}"), 42);
\endrst
*/
format("{}", 42);
format(std::string("{}"), 42);
\endrst
*/
template <typename Char>
class BasicStringRef
{
private:
class BasicStringRef {
private:
const Char *data_;
std::size_t size_;
public:
public:
/**
Constructs a string reference object from a C string and a size.
*/
......@@ -256,33 +250,24 @@ public:
/**
Converts a string reference to an `std::string` object.
*/
operator std::basic_string<Char>() const
{
operator std::basic_string<Char>() const {
return std::basic_string<Char>(data_, size());
}
/**
Returns the pointer to a C string.
*/
const Char *c_str() const
{
return data_;
}
const Char *c_str() const { return data_; }
/**
Returns the string size.
*/
std::size_t size() const
{
return size_;
}
std::size_t size() const { return size_; }
friend bool operator==(BasicStringRef lhs, BasicStringRef rhs)
{
friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) {
return lhs.data_ == rhs.data_;
}
friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs)
{
friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) {
return lhs.data_ != rhs.data_;
}
};
......@@ -291,18 +276,15 @@ typedef BasicStringRef<char> StringRef;
typedef BasicStringRef<wchar_t> WStringRef;
/**
A formatting error such as invalid format string.
A formatting error such as invalid format string.
*/
class FormatError : public std::runtime_error
{
public:
class FormatError : public std::runtime_error {
public:
explicit FormatError(StringRef message)
: std::runtime_error(message.c_str()) {}
};
namespace internal
{
namespace internal {
// The number of characters to store in the MemoryBuffer object itself
// to avoid dynamic memory allocation.
enum { INLINE_BUFFER_SIZE = 500 };
......@@ -310,26 +292,22 @@ enum { INLINE_BUFFER_SIZE = 500 };
#if _SECURE_SCL
// Use checked iterator to avoid warnings on MSVC.
template <typename T>
inline stdext::checked_array_iterator<T*> make_ptr(T *ptr, std::size_t size)
{
inline stdext::checked_array_iterator<T*> make_ptr(T *ptr, std::size_t size) {
return stdext::checked_array_iterator<T*>(ptr, size);
}
#else
template <typename T>
inline T *make_ptr(T *ptr, std::size_t)
{
return ptr;
}
inline T *make_ptr(T *ptr, std::size_t) { return ptr; }
#endif
} // namespace internal
// A buffer for POD types. It supports a subset of std::vector's operations.
/** A buffer supporting a subset of ``std::vector``'s operations. */
template <typename T>
class Buffer
{
private:
class Buffer {
private:
FMT_DISALLOW_COPY_AND_ASSIGN(Buffer);
protected:
protected:
T *ptr_;
std::size_t size_;
std::size_t capacity_;
......@@ -337,112 +315,95 @@ protected:
Buffer(T *ptr = 0, std::size_t capacity = 0)
: ptr_(ptr), size_(0), capacity_(capacity) {}
/**
Increases the buffer capacity to hold at least *size* elements updating
``ptr_`` and ``capacity_``.
*/
virtual void grow(std::size_t size) = 0;
public:
public:
virtual ~Buffer() {}
// Returns the size of this buffer.
std::size_t size() const
{
return size_;
}
/** Returns the size of this buffer. */
std::size_t size() const { return size_; }
// Returns the capacity of this buffer.
std::size_t capacity() const
{
return capacity_;
}
/** Returns the capacity of this buffer. */
std::size_t capacity() const { return capacity_; }
// Resizes the buffer. If T is a POD type new elements are not initialized.
void resize(std::size_t new_size)
{
/**
Resizes the buffer. If T is a POD type new elements may not be initialized.
*/
void resize(std::size_t new_size) {
if (new_size > capacity_)
grow(new_size);
size_ = new_size;
}
// Reserves space to store at least capacity elements.
void reserve(std::size_t capacity)
{
/** Reserves space to store at least *capacity* elements. */
void reserve(std::size_t capacity) {
if (capacity > capacity_)
grow(capacity);
}
void clear() FMT_NOEXCEPT { size_ = 0; }
void push_back(const T &value)
{
void push_back(const T &value) {
if (size_ == capacity_)
grow(size_ + 1);
ptr_[size_++] = value;
}
// Appends data to the end of the buffer.
/** Appends data to the end of the buffer. */
void append(const T *begin, const T *end);
T &operator[](std::size_t index)
{
return ptr_[index];
}
const T &operator[](std::size_t index) const
{
return ptr_[index];
}
T &operator[](std::size_t index) { return ptr_[index]; }
const T &operator[](std::size_t index) const { return ptr_[index]; }
};
template <typename T>
void Buffer<T>::append(const T *begin, const T *end)
{
void Buffer<T>::append(const T *begin, const T *end) {
std::ptrdiff_t num_elements = end - begin;
if (size_ + num_elements > capacity_)
grow(size_ + num_elements);
std::copy(begin, end, make_ptr(ptr_, capacity_) + size_);
std::copy(begin, end, internal::make_ptr(ptr_, capacity_) + size_);
size_ += num_elements;
}
namespace internal {
// A memory buffer for POD types with the first SIZE elements stored in
// the object itself.
template <typename T, std::size_t SIZE, typename Allocator = std::allocator<T> >
class MemoryBuffer : private Allocator, public Buffer<T>
{
private:
class MemoryBuffer : private Allocator, public Buffer<T> {
private:
T data_[SIZE];
// Free memory allocated by the buffer.
void free()
{
void free() {
if (this->ptr_ != data_) this->deallocate(this->ptr_, this->capacity_);
}
protected:
protected:
void grow(std::size_t size);
public:
public:
explicit MemoryBuffer(const Allocator &alloc = Allocator())
: Allocator(alloc), Buffer<T>(data_, SIZE) {}
~MemoryBuffer()
{
free();
}
~MemoryBuffer() { free(); }
#if FMT_USE_RVALUE_REFERENCES
private:
private:
// Move data from other to this buffer.
void move(MemoryBuffer &other)
{
void move(MemoryBuffer &other) {
Allocator &this_alloc = *this, &other_alloc = other;
this_alloc = std::move(other_alloc);
this->size_ = other.size_;
this->capacity_ = other.capacity_;
if (other.ptr_ == other.data_)
{
if (other.ptr_ == other.data_) {
this->ptr_ = data_;
std::copy(other.data_,
other.data_ + this->size_, make_ptr(data_, this->capacity_));
}
else
{
} else {
this->ptr_ = other.ptr_;
// Set pointer to the inline array so that delete is not called
// when freeing.
......@@ -450,14 +411,12 @@ private:
}
}
public:
MemoryBuffer(MemoryBuffer &&other)
{
public:
MemoryBuffer(MemoryBuffer &&other) {
move(other);
}
MemoryBuffer &operator=(MemoryBuffer &&other)
{
MemoryBuffer &operator=(MemoryBuffer &&other) {
assert(this != &other);
free();
move(other);
......@@ -466,15 +425,11 @@ public:
#endif
// Returns a copy of the allocator associated with this buffer.
Allocator get_allocator() const
{
return *this;
}
Allocator get_allocator() const { return *this; }
};
template <typename T, std::size_t SIZE, typename Allocator>
void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size)
{
void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size) {
std::size_t new_capacity =
(std::max)(size, this->capacity_ + this->capacity_ / 2);
T *new_ptr = this->allocate(new_capacity);
......@@ -492,10 +447,19 @@ void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size)
this->deallocate(old_ptr, old_capacity);
}
// A fixed-size buffer.
template <typename Char>
class FixedBuffer : public fmt::Buffer<Char> {
public:
FixedBuffer(Char *array, std::size_t size) : fmt::Buffer<Char>(array, size) {}
protected:
void grow(std::size_t size);
};
#ifndef _MSC_VER
// Portable version of signbit.
inline int getsign(double x)
{
inline int getsign(double x) {
// When compiled in C++11 mode signbit is no longer a macro but a function
// defined in namespace std and the macro is undefined.
# ifdef signbit
......@@ -507,27 +471,14 @@ inline int getsign(double x)
// Portable version of isinf.
# ifdef isinf
inline int isinfinity(double x)
{
return isinf(x);
}
inline int isinfinity(long double x)
{
return isinf(x);
}
inline int isinfinity(double x) { return isinf(x); }
inline int isinfinity(long double x) { return isinf(x); }
# else
inline int isinfinity(double x)
{
return std::isinf(x);
}
inline int isinfinity(long double x)
{
return std::isinf(x);
}
inline int isinfinity(double x) { return std::isinf(x); }
inline int isinfinity(long double x) { return std::isinf(x); }
# endif
#else
inline int getsign(double value)
{
inline int getsign(double value) {
if (value < 0) return 1;
if (value == value) return 0;
int dec = 0, sign = 0;
......@@ -535,20 +486,13 @@ inline int getsign(double value)
_ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign);
return sign;
}
inline int isinfinity(double x)
{
return !_finite(x);
}
inline int isinfinity(long double x)
{
return !_finite(static_cast<double>(x));
}
inline int isinfinity(double x) { return !_finite(x); }
inline int isinfinity(long double x) { return !_finite(static_cast<double>(x)); }
#endif
template <typename Char>
class BasicCharTraits
{
public:
class BasicCharTraits {
public:
#if _SECURE_SCL
typedef stdext::checked_array_iterator<Char*> CharPtr;
#else
......@@ -560,17 +504,13 @@ template <typename Char>
class CharTraits;
template <>
class CharTraits<char> : public BasicCharTraits<char>
{
private:
class CharTraits<char> : public BasicCharTraits<char> {
private:
// Conversion from wchar_t to char is not allowed.
static char convert(wchar_t);
public:
static char convert(char value)
{
return value;
}
static char convert(char value) { return value; }
// Formats a floating-point number.
template <typename T>
......@@ -579,17 +519,10 @@ public:
};
template <>
class CharTraits<wchar_t> : public BasicCharTraits<wchar_t>
{
public:
static wchar_t convert(char value)
{
return value;
}
static wchar_t convert(wchar_t value)
{
return value;
}
class CharTraits<wchar_t> : public BasicCharTraits<wchar_t> {
public:
static wchar_t convert(char value) { return value; }
static wchar_t convert(wchar_t value) { return value; }
template <typename T>
static int format_float(wchar_t *buffer, std::size_t size,
......@@ -598,49 +531,33 @@ public:
// Checks if a number is negative - used to avoid warnings.
template <bool IsSigned>
struct SignChecker
{
struct SignChecker {
template <typename T>
static bool is_negative(T value)
{
return value < 0;
}
static bool is_negative(T value) { return value < 0; }
};
template <>
struct SignChecker<false>
{
struct SignChecker<false> {
template <typename T>
static bool is_negative(T)
{
return false;
}
static bool is_negative(T) { return false; }
};
// Returns true if value is negative, false otherwise.
// Same as (value < 0) but doesn't produce warnings if T is an unsigned type.
template <typename T>
inline bool is_negative(T value)
{
inline bool is_negative(T value) {
return SignChecker<std::numeric_limits<T>::is_signed>::is_negative(value);
}
// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise.
template <bool FitsIn32Bits>
struct TypeSelector
{
typedef uint32_t Type;
};
struct TypeSelector { typedef uint32_t Type; };
template <>
struct TypeSelector<false>
{
typedef uint64_t Type;
};
struct TypeSelector<false> { typedef uint64_t Type; };
template <typename T>
struct IntTraits
{
struct IntTraits {
// Smallest of uint32_t and uint64_t that is large enough to represent
// all values of T.
typedef typename
......@@ -649,10 +566,7 @@ struct IntTraits
// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T.
template <typename T>
struct MakeUnsigned
{
typedef T Type;
};
struct MakeUnsigned { typedef T Type; };
#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \
template <> \
......@@ -670,8 +584,7 @@ void report_unknown_type(char code, const char *type);
// Static data is placed in this class template to allow header-only
// configuration.
template <typename T = void>
struct BasicData
{
struct BasicData {
static const uint32_t POWERS_OF_10_32[];
static const uint64_t POWERS_OF_10_64[];
static const char DIGITS[];
......@@ -690,8 +603,7 @@ typedef BasicData<> Data;
#ifdef FMT_BUILTIN_CLZLL
// Returns the number of decimal digits in n. Leading zeros are not counted
// except for n == 0 in which case count_digits returns 1.
inline unsigned count_digits(uint64_t n)
{
inline unsigned count_digits(uint64_t n) {
// Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
// and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits.
unsigned t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12;
......@@ -699,11 +611,9 @@ inline unsigned count_digits(uint64_t n)
}
#else
// Fallback version of count_digits used when __builtin_clz is not available.
inline unsigned count_digits(uint64_t n)
{
inline unsigned count_digits(uint64_t n) {
unsigned count = 1;
for (;;)
{
for (;;) {
// Integer division is slow so do it for a group of four digits instead
// of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison.
......@@ -719,8 +629,7 @@ inline unsigned count_digits(uint64_t n)
#ifdef FMT_BUILTIN_CLZ
// Optional version of count_digits for better performance on 32-bit platforms.
inline unsigned count_digits(uint32_t n)
{
inline unsigned count_digits(uint32_t n) {
uint32_t t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12;
return t - (n < Data::POWERS_OF_10_32[t]) + 1;
}
......@@ -728,11 +637,9 @@ inline unsigned count_digits(uint32_t n)
// Formats a decimal unsigned integer value writing into buffer.
template <typename UInt, typename Char>
inline void format_decimal(Char *buffer, UInt value, unsigned num_digits)
{
inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
--num_digits;
while (value >= 100)
{
while (value >= 100) {
// Integer division is slow so do it for a group of two digits instead
// of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison.
......@@ -742,8 +649,7 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits)
buffer[num_digits - 1] = Data::DIGITS[index];
num_digits -= 2;
}
if (value < 10)
{
if (value < 10) {
*buffer = static_cast<char>('0' + value);
return;
}
......@@ -755,57 +661,31 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits)
#ifdef _WIN32
// A converter from UTF-8 to UTF-16.
// It is only provided for Windows since other systems support UTF-8 natively.
class UTF8ToUTF16
{
private:
class UTF8ToUTF16 {
private:
MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer_;
public:
public:
explicit UTF8ToUTF16(StringRef s);
operator WStringRef() const
{
return WStringRef(&buffer_[0], size());
}
size_t size() const
{
return buffer_.size() - 1;
}
const wchar_t *c_str() const
{
return &buffer_[0];
}
std::wstring str() const
{
return std::wstring(&buffer_[0], size());
}
operator WStringRef() const { return WStringRef(&buffer_[0], size()); }
size_t size() const { return buffer_.size() - 1; }
const wchar_t *c_str() const { return &buffer_[0]; }
std::wstring str() const { return std::wstring(&buffer_[0], size()); }
};
// A converter from UTF-16 to UTF-8.
// It is only provided for Windows since other systems support UTF-8 natively.
class UTF16ToUTF8
{
private:
class UTF16ToUTF8 {
private:
MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer_;
public:
public:
UTF16ToUTF8() {}
explicit UTF16ToUTF8(WStringRef s);
operator StringRef() const
{
return StringRef(&buffer_[0], size());
}
size_t size() const
{
return buffer_.size() - 1;
}
const char *c_str() const
{
return &buffer_[0];
}
std::string str() const
{
return std::string(&buffer_[0], size());
}
operator StringRef() const { return StringRef(&buffer_[0], size()); }
size_t size() const { return buffer_.size() - 1; }
const char *c_str() const { return &buffer_[0]; }
std::string str() const { return std::string(&buffer_[0], size()); }
// Performs conversion returning a system error code instead of
// throwing exception on conversion error. This method may still throw
......@@ -822,42 +702,30 @@ void format_windows_error(fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT;
#endif
// Computes max(Arg, 1) at compile time. It is used to avoid errors about
// Computes max(N, 1) at compile time. It is used to avoid errors about
// allocating an array of 0 size.
template <unsigned Arg>
struct NonZero
{
enum { VALUE = Arg };
template <unsigned N>
struct NonZero {
enum { VALUE = N > 0 ? N : 1 };
};
template <>
struct NonZero<0>
{
enum { VALUE = 1 };
};
// The value of a formatting argument. It is a POD type to allow storage in
// internal::MemoryBuffer.
struct Value
{
// A formatting argument value.
struct Value {
template <typename Char>
struct StringValue
{
struct StringValue {
const Char *value;
std::size_t size;
};
typedef void(*FormatFunc)(
typedef void (*FormatFunc)(
void *formatter, const void *arg, void *format_str_ptr);
struct CustomValue
{
struct CustomValue {
const void *value;
FormatFunc format;
};
union
{
union {
int int_value;
unsigned uint_value;
LongLong long_long_value;
......@@ -871,12 +739,8 @@ struct Value
StringValue<wchar_t> wstring;
CustomValue custom;
};
};
struct Arg : Value
{
enum Type
{
enum Type {
NONE,
// Integer types should go first,
INT, UINT, LONG_LONG, ULONG_LONG, CHAR, LAST_INTEGER_TYPE = CHAR,
......@@ -884,33 +748,78 @@ struct Arg : Value
DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE,
CSTRING, STRING, WSTRING, POINTER, CUSTOM
};
};
// A formatting argument. It is a POD type to allow storage in
// internal::MemoryBuffer.
struct Arg : Value {
Type type;
};
template <typename T>
template <typename T = void>
struct None {};
// A helper class template to enable or disable overloads taking wide
// characters and strings in MakeValue.
template <typename T, typename Char>
struct WCharHelper
{
struct WCharHelper {
typedef None<T> Supported;
typedef T Unsupported;
};
template <typename T>
struct WCharHelper<T, wchar_t>
{
struct WCharHelper<T, wchar_t> {
typedef T Supported;
typedef None<T> Unsupported;
};
// Makes a Value object from any type.
template <typename T>
class IsConvertibleToInt {
private:
typedef char yes[1];
typedef char no[2];
static const T &get();
static yes &check(fmt::ULongLong);
static no &check(...);
public:
enum { value = (sizeof(check(get())) == sizeof(yes)) };
};
#define FMT_CONVERTIBLE_TO_INT(Type) \
template <> \
class IsConvertibleToInt<Type> { \
public: \
enum { value = 1 }; \
}
// Silence warnings about convering float to int.
FMT_CONVERTIBLE_TO_INT(float);
FMT_CONVERTIBLE_TO_INT(double);
FMT_CONVERTIBLE_TO_INT(long double);
template<bool B, class T = void>
struct EnableIf {};
template<class T>
struct EnableIf<true, T> { typedef T type; };
template<bool B, class T, class F>
struct Conditional { typedef T type; };
template<class T, class F>
struct Conditional<false, T, F> { typedef F type; };
// A helper function to suppress bogus "conditional expression is constant"
// warnings.
inline bool check(bool value) { return value; }
// Makes an Arg object from any type.
template <typename Char>
class MakeValue : public Value
{
private:
class MakeValue : public Arg {
private:
// The following two methods are private to disallow formatting of
// arbitrary pointers. If you want to output a pointer cast it to
// "void *" or "const void *". In particular, this forbids formatting
......@@ -931,14 +840,12 @@ private:
MakeValue(typename WCharHelper<const std::wstring &, Char>::Unsupported);
MakeValue(typename WCharHelper<WStringRef, Char>::Unsupported);
void set_string(StringRef str)
{
void set_string(StringRef str) {
string.value = str.c_str();
string.size = str.size();
}
void set_string(WStringRef str)
{
void set_string(WStringRef str) {
wstring.value = str.c_str();
wstring.size = str.size();
}
......@@ -946,14 +853,13 @@ private:
// Formats an argument of a custom type, such as a user-defined class.
template <typename T>
static void format_custom_arg(
void *formatter, const void *arg, void *format_str_ptr)
{
void *formatter, const void *arg, void *format_str_ptr) {
format(*static_cast<BasicFormatter<Char>*>(formatter),
*static_cast<const Char**>(format_str_ptr),
*static_cast<const T*>(arg));
}
public:
public:
MakeValue() {}
#define FMT_MAKE_VALUE(Type, field, TYPE) \
......@@ -966,29 +872,25 @@ public:
FMT_MAKE_VALUE(int, int_value, INT)
FMT_MAKE_VALUE(unsigned, uint_value, UINT)
MakeValue(long value)
{
MakeValue(long value) {
// 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.
if (sizeof(long) == sizeof(int))
if (check(sizeof(long) == sizeof(int)))
int_value = static_cast<int>(value);
else
long_long_value = value;
}
static uint64_t type(long)
{
static uint64_t type(long) {
return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG;
}
MakeValue(unsigned long value)
{
if (sizeof(unsigned long) == sizeof(unsigned))
MakeValue(unsigned long value) {
if (check(sizeof(unsigned long) == sizeof(unsigned)))
uint_value = static_cast<unsigned>(value);
else
ulong_long_value = value;
}
static uint64_t type(unsigned long)
{
static uint64_t type(unsigned long) {
return sizeof(unsigned long) == sizeof(unsigned) ?
Arg::UINT : Arg::ULONG_LONG;
}
......@@ -1002,14 +904,10 @@ public:
FMT_MAKE_VALUE(unsigned char, int_value, CHAR)
FMT_MAKE_VALUE(char, int_value, CHAR)
MakeValue(typename WCharHelper<wchar_t, Char>::Supported value)
{
MakeValue(typename WCharHelper<wchar_t, Char>::Supported value) {
int_value = value;
}
static uint64_t type(wchar_t)
{
return Arg::CHAR;
}
static uint64_t type(wchar_t) { return Arg::CHAR; }
#define FMT_MAKE_STR_VALUE(Type, TYPE) \
MakeValue(Type value) { set_string(value); } \
......@@ -1037,15 +935,21 @@ public:
FMT_MAKE_VALUE(const void *, pointer, POINTER)
template <typename T>
MakeValue(const T &value)
{
MakeValue(const T &value,
typename EnableIf<!IsConvertibleToInt<T>::value, int>::type = 0) {
custom.value = &value;
custom.format = &format_custom_arg<T>;
}
template <typename T>
MakeValue(const T &value,
typename EnableIf<IsConvertibleToInt<T>::value, int>::type = 0) {
int_value = value;
}
template <typename T>
static uint64_t type(const T &)
{
return Arg::CUSTOM;
static uint64_t type(const T &) {
return IsConvertibleToInt<T>::value ? Arg::INT : Arg::CUSTOM;
}
};
......@@ -1072,75 +976,61 @@ public:
// ArgVisitor uses the curiously recurring template pattern:
// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
template <typename Impl, typename Result>
class ArgVisitor
{
public:
Result visit_unhandled_arg()
{
class ArgVisitor {
public:
void report_unhandled_arg() {}
Result visit_unhandled_arg() {
FMT_DISPATCH(report_unhandled_arg());
return Result();
}
Result visit_int(int value)
{
Result visit_int(int value) {
return FMT_DISPATCH(visit_any_int(value));
}
Result visit_long_long(LongLong value)
{
Result visit_long_long(LongLong value) {
return FMT_DISPATCH(visit_any_int(value));
}
Result visit_uint(unsigned value)
{
Result visit_uint(unsigned value) {
return FMT_DISPATCH(visit_any_int(value));
}
Result visit_ulong_long(ULongLong value)
{
Result visit_ulong_long(ULongLong value) {
return FMT_DISPATCH(visit_any_int(value));
}
Result visit_char(int value)
{
Result visit_char(int value) {
return FMT_DISPATCH(visit_any_int(value));
}
template <typename T>
Result visit_any_int(T)
{
Result visit_any_int(T) {
return FMT_DISPATCH(visit_unhandled_arg());
}
Result visit_double(double value)
{
Result visit_double(double value) {
return FMT_DISPATCH(visit_any_double(value));
}
Result visit_long_double(long double value)
{
Result visit_long_double(long double value) {
return FMT_DISPATCH(visit_any_double(value));
}
template <typename T>
Result visit_any_double(T)
{
Result visit_any_double(T) {
return FMT_DISPATCH(visit_unhandled_arg());
}
Result visit_string(Arg::StringValue<char>)
{
Result visit_string(Arg::StringValue<char>) {
return FMT_DISPATCH(visit_unhandled_arg());
}
Result visit_wstring(Arg::StringValue<wchar_t>)
{
Result visit_wstring(Arg::StringValue<wchar_t>) {
return FMT_DISPATCH(visit_unhandled_arg());
}
Result visit_pointer(const void *)
{
Result visit_pointer(const void *) {
return FMT_DISPATCH(visit_unhandled_arg());
}
Result visit_custom(Arg::CustomValue)
{
Result visit_custom(Arg::CustomValue) {
return FMT_DISPATCH(visit_unhandled_arg());
}
Result visit(const Arg &arg)
{
switch (arg.type)
{
Result visit(const Arg &arg) {
switch (arg.type) {
default:
assert(false);
return Result();
......@@ -1158,9 +1048,8 @@ public:
return FMT_DISPATCH(visit_long_double(arg.long_double_value));
case Arg::CHAR:
return FMT_DISPATCH(visit_char(arg.int_value));
case Arg::CSTRING:
{
Value::StringValue<char> str = arg.string;
case Arg::CSTRING: {
Arg::StringValue<char> str = arg.string;
str.size = 0;
return FMT_DISPATCH(visit_string(str));
}
......@@ -1176,9 +1065,8 @@ public:
}
};
class RuntimeError : public std::runtime_error
{
protected:
class RuntimeError : public std::runtime_error {
protected:
RuntimeError() : std::runtime_error("") {}
};
......@@ -1186,66 +1074,88 @@ template <typename Char>
class ArgFormatter;
} // namespace internal
/**
An argument list.
*/
class ArgList
{
private:
/** An argument list. */
class ArgList {
private:
// To reduce compiled code size per formatting function call, types of first
// MAX_PACKED_ARGS arguments are passed in the types_ field.
uint64_t types_;
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_.
// This is done to reduce compiled code size as storing larger objects
// may require more code (at least on x86-64) even if the same amount of
// data is actually copied to stack. It saves ~10% on the bloat test.
const internal::Value *values_;
const internal::Arg *args_;
};
public:
// Maximum number of arguments that can be passed in ArgList.
enum { MAX_ARGS = 16 };
internal::Arg::Type type(unsigned index) const {
unsigned shift = index * 4;
uint64_t mask = 0xf;
return static_cast<internal::Arg::Type>(
(types_ & (mask << shift)) >> shift);
}
public:
// Maximum number of arguments with packed types.
enum { MAX_PACKED_ARGS = 16 };
ArgList() : types_(0) {}
// TODO: MakeArgList(const Args &...)
ArgList(ULongLong types, const internal::Value *values)
: types_(types), values_(values) {}
ArgList(ULongLong types, const internal::Arg *args)
: types_(types), args_(args) {}
/**
Returns the argument at specified index.
*/
internal::Arg operator[](unsigned index) const
{
/** Returns the argument at specified index. */
internal::Arg operator[](unsigned index) const {
using internal::Arg;
Arg arg;
if (index >= MAX_ARGS)
{
bool use_values = type(MAX_PACKED_ARGS - 1) == Arg::NONE;
if (index < MAX_PACKED_ARGS) {
Arg::Type arg_type = type(index);
internal::Value &val = arg;
if (arg_type != Arg::NONE)
val = use_values ? values_[index] : args_[index];
arg.type = arg_type;
return arg;
}
if (use_values) {
// The index is greater than the number of arguments that can be stored
// in values, so return a "none" argument.
arg.type = Arg::NONE;
return arg;
}
unsigned shift = index * 4;
uint64_t mask = 0xf;
Arg::Type type =
static_cast<Arg::Type>((types_ & (mask << shift)) >> shift);
arg.type = type;
if (type != Arg::NONE)
{
internal::Value &value = arg;
value = values_[index];
for (unsigned i = MAX_PACKED_ARGS; i <= index; ++i) {
if (args_[i].type == Arg::NONE)
return args_[i];
}
return arg;
return args_[index];
}
};
struct FormatSpec;
namespace internal
{
namespace internal {
template <std::size_t NUM_ARGS>
struct SelectValueType {
typedef typename Conditional<
(NUM_ARGS < ArgList::MAX_PACKED_ARGS), Value, Arg>::type Type;
};
class FormatterBase
{
private:
class FormatterBase {
private:
ArgList args_;
int next_arg_index_;
// Returns the argument with specified index.
Arg do_get_arg(unsigned arg_index, const char *&error);
protected:
void set_args(const ArgList &args)
{
protected:
void set_args(const ArgList &args) {
args_ = args;
next_arg_index_ = 0;
}
......@@ -1258,8 +1168,7 @@ protected:
Arg get_arg(unsigned arg_index, const char *&error);
template <typename Char>
void write(BasicWriter<Char> &w, const Char *start, const Char *end)
{
void write(BasicWriter<Char> &w, const Char *start, const Char *end) {
if (start != end)
w << BasicStringRef<Char>(start, end - start);
}
......@@ -1267,9 +1176,8 @@ protected:
// A printf formatter.
template <typename Char>
class PrintfFormatter : private FormatterBase
{
private:
class PrintfFormatter : private FormatterBase {
private:
void parse_flags(FormatSpec &spec, const Char *&s);
// Returns the argument with specified index or, if arg_index is equal
......@@ -1280,7 +1188,7 @@ private:
// Parses argument index, flags and width and returns the argument index.
unsigned parse_header(const Char *&s, FormatSpec &spec);
public:
public:
void format(BasicWriter<Char> &writer,
BasicStringRef<Char> format_str, const ArgList &args);
};
......@@ -1288,9 +1196,8 @@ public:
// A formatter.
template <typename Char>
class BasicFormatter : private internal::FormatterBase
{
private:
class BasicFormatter : private internal::FormatterBase {
private:
BasicWriter<Char> &writer_;
const Char *start_;
......@@ -1299,27 +1206,22 @@ private:
// Parses argument index and returns corresponding argument.
internal::Arg parse_arg_index(const Char *&s);
public:
public:
explicit BasicFormatter(BasicWriter<Char> &w) : writer_(w) {}
BasicWriter<Char> &writer()
{
return writer_;
}
BasicWriter<Char> &writer() { return writer_; }
void format(BasicStringRef<Char> format_str, const ArgList &args);
const Char *format(const Char *&format_str, const internal::Arg &arg);
};
enum Alignment
{
enum Alignment {
ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC
};
// Flags.
enum
{
enum {
SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8,
CHAR_FLAG = 0x10 // Argument has char type - used in error reporting.
};
......@@ -1329,37 +1231,17 @@ struct EmptySpec {};
// A type specifier.
template <char TYPE>
struct TypeSpec : EmptySpec
{
Alignment align() const
{
return ALIGN_DEFAULT;
}
unsigned width() const
{
return 0;
}
int precision() const
{
return -1;
}
bool flag(unsigned) const
{
return false;
}
char type() const
{
return TYPE;
}
char fill() const
{
return ' ';
}
struct TypeSpec : EmptySpec {
Alignment align() const { return ALIGN_DEFAULT; }
unsigned width() const { return 0; }
int precision() const { return -1; }
bool flag(unsigned) const { return false; }
char type() const { return TYPE; }
char fill() const { return ' '; }
};
// A width specifier.
struct WidthSpec
{
struct WidthSpec {
unsigned width_;
// Fill is always wchar_t and cast to char if necessary to avoid having
// two specialization of WidthSpec and its subclasses.
......@@ -1367,54 +1249,33 @@ struct WidthSpec
WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {}
unsigned width() const
{
return width_;
}
wchar_t fill() const
{
return fill_;
}
unsigned width() const { return width_; }
wchar_t fill() const { return fill_; }
};
// An alignment specifier.
struct AlignSpec : WidthSpec
{
struct AlignSpec : WidthSpec {
Alignment align_;
AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT)
: WidthSpec(width, fill), align_(align) {}
Alignment align() const
{
return align_;
}
Alignment align() const { return align_; }
int precision() const
{
return -1;
}
int precision() const { return -1; }
};
// An alignment and type specifier.
template <char TYPE>
struct AlignTypeSpec : AlignSpec
{
struct AlignTypeSpec : AlignSpec {
AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {}
bool flag(unsigned) const
{
return false;
}
char type() const
{
return TYPE;
}
bool flag(unsigned) const { return false; }
char type() const { return TYPE; }
};
// A full format specifier.
struct FormatSpec : AlignSpec
{
struct FormatSpec : AlignSpec {
unsigned flags_;
int precision_;
char type_;
......@@ -1423,90 +1284,73 @@ struct FormatSpec : AlignSpec
unsigned width = 0, char type = 0, wchar_t fill = ' ')
: AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {}
bool flag(unsigned f) const
{
return (flags_ & f) != 0;
}
int precision() const
{
return precision_;
}
char type() const
{
return type_;
}
bool flag(unsigned f) const { return (flags_ & f) != 0; }
int precision() const { return precision_; }
char type() const { return type_; }
};
// An integer format specifier.
template <typename T, typename SpecT = TypeSpec<0>, typename Char = char>
class IntFormatSpec : public SpecT
{
private:
class IntFormatSpec : public SpecT {
private:
T value_;
public:
public:
IntFormatSpec(T val, const SpecT &spec = SpecT())
: SpecT(spec), value_(val) {}
T value() const
{
return value_;
}
T value() const { return value_; }
};
// A string format specifier.
template <typename T>
class StrFormatSpec : public AlignSpec
{
private:
class StrFormatSpec : public AlignSpec {
private:
const T *str_;
public:
public:
StrFormatSpec(const T *str, unsigned width, wchar_t fill)
: AlignSpec(width, fill), str_(str) {}
const T *str() const
{
return str_;
}
const T *str() const { return str_; }
};
/**
Returns an integer format specifier to format the value in base 2.
*/
Returns an integer format specifier to format the value in base 2.
*/
IntFormatSpec<int, TypeSpec<'b'> > bin(int value);
/**
Returns an integer format specifier to format the value in base 8.
*/
Returns an integer format specifier to format the value in base 8.
*/
IntFormatSpec<int, TypeSpec<'o'> > oct(int value);
/**
Returns an integer format specifier to format the value in base 16 using
lower-case letters for the digits above 9.
*/
Returns an integer format specifier to format the value in base 16 using
lower-case letters for the digits above 9.
*/
IntFormatSpec<int, TypeSpec<'x'> > hex(int value);
/**
Returns an integer formatter format specifier to format in base 16 using
upper-case letters for the digits above 9.
*/
Returns an integer formatter format specifier to format in base 16 using
upper-case letters for the digits above 9.
*/
IntFormatSpec<int, TypeSpec<'X'> > hexu(int value);
/**
\rst
Returns an integer format specifier to pad the formatted argument with the
fill character to the specified width using the default (right) numeric
alignment.
\rst
Returns an integer format specifier to pad the formatted argument with the
fill character to the specified width using the default (right) numeric
alignment.
**Example**::
**Example**::
MemoryWriter out;
out << pad(hex(0xcafe), 8, '0');
// out.str() == "0000cafe"
MemoryWriter out;
out << pad(hex(0xcafe), 8, '0');
// out.str() == "0000cafe"
\endrst
*/
\endrst
*/
template <char TYPE_CODE, typename Char>
IntFormatSpec<int, AlignTypeSpec<TYPE_CODE>, Char> pad(
int value, unsigned width, Char fill = ' ');
......@@ -1514,26 +1358,26 @@ IntFormatSpec<int, AlignTypeSpec<TYPE_CODE>, Char> pad(
#define FMT_DEFINE_INT_FORMATTERS(TYPE) \
inline IntFormatSpec<TYPE, TypeSpec<'b'> > bin(TYPE value) { \
return IntFormatSpec<TYPE, TypeSpec<'b'> >(value, TypeSpec<'b'>()); \
} \
} \
\
inline IntFormatSpec<TYPE, TypeSpec<'o'> > oct(TYPE value) { \
return IntFormatSpec<TYPE, TypeSpec<'o'> >(value, TypeSpec<'o'>()); \
} \
} \
\
inline IntFormatSpec<TYPE, TypeSpec<'x'> > hex(TYPE value) { \
return IntFormatSpec<TYPE, TypeSpec<'x'> >(value, TypeSpec<'x'>()); \
} \
} \
\
inline IntFormatSpec<TYPE, TypeSpec<'X'> > hexu(TYPE value) { \
return IntFormatSpec<TYPE, TypeSpec<'X'> >(value, TypeSpec<'X'>()); \
} \
} \
\
template <char TYPE_CODE> \
inline IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE> > pad( \
IntFormatSpec<TYPE, TypeSpec<TYPE_CODE> > f, unsigned width) { \
return IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE> >( \
f.value(), AlignTypeSpec<TYPE_CODE>(width, ' ')); \
} \
} \
\
/* For compatibility with older compilers we provide two overloads for pad, */ \
/* one that takes a fill character and one that doesn't. In the future this */ \
......@@ -1545,20 +1389,20 @@ inline IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE>, Char> pad( \
unsigned width, Char fill) { \
return IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE>, Char>( \
f.value(), AlignTypeSpec<TYPE_CODE>(width, fill)); \
} \
} \
\
inline IntFormatSpec<TYPE, AlignTypeSpec<0> > pad( \
TYPE value, unsigned width) { \
return IntFormatSpec<TYPE, AlignTypeSpec<0> >( \
value, AlignTypeSpec<0>(width, ' ')); \
} \
} \
\
template <typename Char> \
inline IntFormatSpec<TYPE, AlignTypeSpec<0>, Char> pad( \
TYPE value, unsigned width, Char fill) { \
return IntFormatSpec<TYPE, AlignTypeSpec<0>, Char>( \
value, AlignTypeSpec<0>(width, fill)); \
}
}
FMT_DEFINE_INT_FORMATTERS(int)
FMT_DEFINE_INT_FORMATTERS(long)
......@@ -1568,27 +1412,25 @@ FMT_DEFINE_INT_FORMATTERS(LongLong)
FMT_DEFINE_INT_FORMATTERS(ULongLong)
/**
\rst
Returns a string formatter that pads the formatted argument with the fill
character to the specified width using the default (left) string alignment.
\rst
Returns a string formatter that pads the formatted argument with the fill
character to the specified width using the default (left) string alignment.
**Example**::
**Example**::
std::string s = str(MemoryWriter() << pad("abc", 8));
// s == "abc "
std::string s = str(MemoryWriter() << pad("abc", 8));
// s == "abc "
\endrst
*/
\endrst
*/
template <typename Char>
inline StrFormatSpec<Char> pad(
const Char *str, unsigned width, Char fill = ' ')
{
const Char *str, unsigned width, Char fill = ' ') {
return StrFormatSpec<Char>(str, width, fill);
}
inline StrFormatSpec<wchar_t> pad(
const wchar_t *str, unsigned width, char fill = ' ')
{
const wchar_t *str, unsigned width, char fill = ' ') {
return StrFormatSpec<wchar_t>(str, width, fill);
}
......@@ -1611,29 +1453,20 @@ inline StrFormatSpec<wchar_t> pad(
# define FMT_GEN14(f) FMT_GEN13(f), f(13)
# define FMT_GEN15(f) FMT_GEN14(f), f(14)
namespace internal
{
inline uint64_t make_type()
{
return 0;
}
namespace internal {
inline uint64_t make_type() { return 0; }
template <typename T>
inline uint64_t make_type(const T &arg)
{
return MakeValue<char>::type(arg);
}
inline uint64_t make_type(const T &arg) { return MakeValue<char>::type(arg); }
#if FMT_USE_VARIADIC_TEMPLATES
template <typename Arg, typename... Args>
inline uint64_t make_type(const Arg &first, const Args & ... tail)
{
inline uint64_t make_type(const Arg &first, const Args & ... tail) {
return make_type(first) | (make_type(tail...) << 4);
}
#else
struct ArgType
{
struct ArgType {
uint64_t type;
ArgType() : type(0) {}
......@@ -1644,8 +1477,7 @@ struct ArgType
# define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType()
inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT))
{
inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) {
return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) |
(t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) |
(t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) |
......@@ -1664,24 +1496,25 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT))
// Defines a variadic function returning void.
# define FMT_VARIADIC_VOID(func, arg_type) \
template <typename... Args> \
void func(arg_type arg1, const Args & ... args) { \
const fmt::internal::Value values[ \
fmt::internal::NonZero<sizeof...(Args)>::VALUE] = { \
fmt::internal::MakeValue<Char>(args)... \
void func(arg_type arg0, const Args & ... args) { \
namespace internal = fmt::internal; \
typedef typename internal::SelectValueType<sizeof...(Args)>::Type Value; \
const Value array[internal::NonZero<sizeof...(Args)>::VALUE] = { \
internal::MakeValue<Char>(args)... \
}; \
func(arg1, ArgList(fmt::internal::make_type(args...), values)); \
func(arg0, ArgList(internal::make_type(args...), array)); \
}
// Defines a variadic constructor.
# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \
template <typename... Args> \
ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \
using fmt::internal::MakeValue; \
const fmt::internal::Value values[ \
fmt::internal::NonZero<sizeof...(Args)>::VALUE] = { \
MakeValue<Char>(args)... \
namespace internal = fmt::internal; \
typedef typename internal::SelectValueType<sizeof...(Args)>::Type Value; \
const Value array[internal::NonZero<sizeof...(Args)>::VALUE] = { \
internal::MakeValue<Char>(args)... \
}; \
func(arg0, arg1, ArgList(fmt::internal::make_type(args...), values)); \
func(arg0, arg1, ArgList(internal::make_type(args...), array)); \
}
#else
......@@ -1694,9 +1527,9 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT))
# define FMT_WRAP1(func, arg_type, n) \
template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \
inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \
const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF)}; \
const fmt::internal::Value values[] = {FMT_GEN(n, FMT_MAKE_REF)}; \
func(arg1, fmt::ArgList( \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), values)); \
}
// Emulates a variadic function returning void on a pre-C++11 compiler.
......@@ -1711,9 +1544,9 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT))
# define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \
template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \
ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \
const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF)}; \
const fmt::internal::Value values[] = {FMT_GEN(n, FMT_MAKE_REF)}; \
func(arg0, arg1, fmt::ArgList( \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), values)); \
}
// Emulates a variadic constructor on a pre-C++11 compiler.
......@@ -1753,22 +1586,21 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT))
FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8), f(x9, 9)
/**
An error returned by an operating system or a language runtime,
for example a file opening error.
An error returned by an operating system or a language runtime,
for example a file opening error.
*/
class SystemError : public internal::RuntimeError
{
private:
class SystemError : public internal::RuntimeError {
private:
void init(int err_code, StringRef format_str, ArgList args);
protected:
protected:
int error_code_;
typedef char Char; // For FMT_VARIADIC_CTOR.
SystemError() {}
public:
public:
/**
\rst
Constructs a :class:`fmt::SystemError` object with the description
......@@ -1794,42 +1626,37 @@ public:
throw fmt::SystemError(errno, "cannot open file '{}'", filename);
\endrst
*/
SystemError(int error_code, StringRef message)
{
SystemError(int error_code, StringRef message) {
init(error_code, message, ArgList());
}
FMT_VARIADIC_CTOR(SystemError, init, int, StringRef)
int error_code() const
{
return error_code_;
}
int error_code() const { return error_code_; }
};
/**
\rst
This template provides operations for formatting and writing data into
a character stream. The output is stored in a buffer provided by a subclass
such as :class:`fmt::BasicMemoryWriter`.
You can use one of the following typedefs for common character types:
+---------+----------------------+
| Type | Definition |
+=========+======================+
| Writer | BasicWriter<char> |
+---------+----------------------+
| WWriter | BasicWriter<wchar_t> |
+---------+----------------------+
\endrst
*/
\rst
This template provides operations for formatting and writing data into
a character stream. The output is stored in a buffer provided by a subclass
such as :class:`fmt::BasicMemoryWriter`.
You can use one of the following typedefs for common character types:
+---------+----------------------+
| Type | Definition |
+=========+======================+
| Writer | BasicWriter<char> |
+---------+----------------------+
| WWriter | BasicWriter<wchar_t> |
+---------+----------------------+
\endrst
*/
template <typename Char>
class BasicWriter
{
private:
class BasicWriter {
private:
// Output buffer.
internal::Buffer<Char> &buffer_;
Buffer<Char> &buffer_;
FMT_DISALLOW_COPY_AND_ASSIGN(BasicWriter);
......@@ -1837,15 +1664,9 @@ private:
#if _SECURE_SCL
// Returns pointer value.
static Char *get(CharPtr p)
{
return p.base();
}
static Char *get(CharPtr p) { return p.base(); }
#else
static Char *get(Char *p)
{
return p;
}
static Char *get(Char *p) { return p; }
#endif
// Fills the padding around the content and returns the pointer to the
......@@ -1855,8 +1676,7 @@ private:
// Grows the buffer by n characters and returns a pointer to the newly
// allocated area.
CharPtr grow_buffer(std::size_t n)
{
CharPtr grow_buffer(std::size_t n) {
std::size_t size = buffer_.size();
buffer_.resize(size + n);
return internal::make_ptr(&buffer_[size], n);
......@@ -1864,8 +1684,7 @@ private:
// Prepare a buffer for integer formatting.
CharPtr prepare_int_buffer(unsigned num_digits,
const EmptySpec &, const char *prefix, unsigned prefix_size)
{
const EmptySpec &, const char *prefix, unsigned prefix_size) {
unsigned size = prefix_size + num_digits;
CharPtr p = grow_buffer(size);
std::copy(prefix, prefix + prefix_size, p);
......@@ -1903,8 +1722,7 @@ private:
// Appends floating-point length specifier to the format string.
// The second argument is only used for overload resolution.
void append_float_length(Char *&format_ptr, long double)
{
void append_float_length(Char *&format_ptr, long double) {
*format_ptr++ = 'L';
}
......@@ -1914,13 +1732,13 @@ private:
friend class internal::ArgFormatter<Char>;
friend class internal::PrintfFormatter<Char>;
protected:
protected:
/**
Constructs a ``BasicWriter`` object.
*/
explicit BasicWriter(internal::Buffer<Char> &b) : buffer_(b) {}
explicit BasicWriter(Buffer<Char> &b) : buffer_(b) {}
public:
public:
/**
Destroys a ``BasicWriter`` object.
*/
......@@ -1929,26 +1747,19 @@ public:
/**
Returns the total number of characters written.
*/
std::size_t size() const
{
return buffer_.size();
}
std::size_t size() const { return buffer_.size(); }
/**
Returns a pointer to the output buffer content. No terminating null
character is appended.
*/
const Char *data() const FMT_NOEXCEPT
{
return &buffer_[0];
}
const Char *data() const FMT_NOEXCEPT { return &buffer_[0]; }
/**
Returns a pointer to the output buffer content with terminating null
character appended.
*/
const Char *c_str() const
{
const Char *c_str() const {
std::size_t size = buffer_.size();
buffer_.reserve(size + 1);
buffer_[size] = '\0';
......@@ -1958,8 +1769,7 @@ public:
/**
Returns the content of the output buffer as an `std::string`.
*/
std::basic_string<Char> str() const
{
std::basic_string<Char> str() const {
return std::basic_string<Char>(&buffer_[0], buffer_.size());
}
......@@ -1988,43 +1798,35 @@ public:
See also :ref:`syntax`.
\endrst
*/
void write(BasicStringRef<Char> format, ArgList args)
{
void write(BasicStringRef<Char> format, ArgList args) {
BasicFormatter<Char>(*this).format(format, args);
}
FMT_VARIADIC_VOID(write, BasicStringRef<Char>)
BasicWriter &operator<<(int value)
{
BasicWriter &operator<<(int value) {
return *this << IntFormatSpec<int>(value);
}
BasicWriter &operator<<(unsigned value)
{
BasicWriter &operator<<(unsigned value) {
return *this << IntFormatSpec<unsigned>(value);
}
BasicWriter &operator<<(long value)
{
BasicWriter &operator<<(long value) {
return *this << IntFormatSpec<long>(value);
}
BasicWriter &operator<<(unsigned long value)
{
BasicWriter &operator<<(unsigned long value) {
return *this << IntFormatSpec<unsigned long>(value);
}
BasicWriter &operator<<(LongLong value)
{
BasicWriter &operator<<(LongLong value) {
return *this << IntFormatSpec<LongLong>(value);
}
/**
Formats *value* and writes it to the stream.
*/
BasicWriter &operator<<(ULongLong value)
{
BasicWriter &operator<<(ULongLong value) {
return *this << IntFormatSpec<ULongLong>(value);
}
BasicWriter &operator<<(double value)
{
BasicWriter &operator<<(double value) {
write_double(value, FormatSpec());
return *this;
}
......@@ -2033,8 +1835,7 @@ public:
Formats *value* using the general format for floating-point numbers
(``'g'``) and writes it to the stream.
*/
BasicWriter &operator<<(long double value)
{
BasicWriter &operator<<(long double value) {
write_double(value, FormatSpec());
return *this;
}
......@@ -2042,15 +1843,13 @@ public:
/**
Writes a character to the stream.
*/
BasicWriter &operator<<(char value)
{
BasicWriter &operator<<(char value) {
buffer_.push_back(value);
return *this;
}
BasicWriter &operator<<(
typename internal::WCharHelper<wchar_t, Char>::Supported value)
{
typename internal::WCharHelper<wchar_t, Char>::Supported value) {
buffer_.push_back(value);
return *this;
}
......@@ -2058,24 +1857,21 @@ public:
/**
Writes *value* to the stream.
*/
BasicWriter &operator<<(fmt::BasicStringRef<Char> value)
{
BasicWriter &operator<<(fmt::BasicStringRef<Char> value) {
const Char *str = value.c_str();
buffer_.append(str, str + value.size());
return *this;
}
template <typename T, typename Spec, typename FillChar>
BasicWriter &operator<<(IntFormatSpec<T, Spec, FillChar> spec)
{
BasicWriter &operator<<(IntFormatSpec<T, Spec, FillChar> spec) {
internal::CharTraits<Char>::convert(FillChar());
write_int(spec.value(), spec);
return *this;
}
template <typename StrChar>
BasicWriter &operator<<(const StrFormatSpec<StrChar> &spec)
{
BasicWriter &operator<<(const StrFormatSpec<StrChar> &spec) {
const StrChar *s = spec.str();
// TODO: error if fill is not convertible to Char
write_str(s, std::char_traits<Char>::length(s), spec);
......@@ -2088,29 +1884,20 @@ public:
template <typename Char>
template <typename StrChar>
typename BasicWriter<Char>::CharPtr BasicWriter<Char>::write_str(
const StrChar *s, std::size_t size, const AlignSpec &spec)
{
const StrChar *s, std::size_t size, const AlignSpec &spec) {
CharPtr out = CharPtr();
if (spec.width() > size)
{
if (spec.width() > size) {
out = grow_buffer(spec.width());
Char fill = static_cast<Char>(spec.fill());
if (spec.align() == ALIGN_RIGHT)
{
if (spec.align() == ALIGN_RIGHT) {
std::fill_n(out, spec.width() - size, fill);
out += spec.width() - size;
}
else if (spec.align() == ALIGN_CENTER)
{
} else if (spec.align() == ALIGN_CENTER) {
out = fill_padding(out, spec.width(), size, fill);
}
else
{
} else {
std::fill_n(out + size, spec.width() - size, fill);
}
}
else
{
} else {
out = grow_buffer(size);
}
std::copy(s, s + size, out);
......@@ -2119,10 +1906,9 @@ typename BasicWriter<Char>::CharPtr BasicWriter<Char>::write_str(
template <typename Char>
typename BasicWriter<Char>::CharPtr
BasicWriter<Char>::fill_padding(
BasicWriter<Char>::fill_padding(
CharPtr buffer, unsigned total_size,
std::size_t content_size, wchar_t fill)
{
std::size_t content_size, wchar_t fill) {
std::size_t padding = total_size - content_size;
std::size_t left_padding = padding / 2;
Char fill_char = static_cast<Char>(fill);
......@@ -2136,15 +1922,13 @@ BasicWriter<Char>::fill_padding(
template <typename Char>
template <typename Spec>
typename BasicWriter<Char>::CharPtr
BasicWriter<Char>::prepare_int_buffer(
BasicWriter<Char>::prepare_int_buffer(
unsigned num_digits, const Spec &spec,
const char *prefix, unsigned prefix_size)
{
const char *prefix, unsigned prefix_size) {
unsigned width = spec.width();
Alignment align = spec.align();
Char fill = static_cast<Char>(spec.fill());
if (spec.precision() > static_cast<int>(num_digits))
{
if (spec.precision() > static_cast<int>(num_digits)) {
// Octal prefix '0' is counted as a digit, so ignore it if precision
// is specified.
if (prefix_size > 0 && prefix[prefix_size - 1] == '0')
......@@ -2155,53 +1939,41 @@ BasicWriter<Char>::prepare_int_buffer(
return prepare_int_buffer(num_digits, subspec, prefix, prefix_size);
buffer_.reserve(width);
unsigned fill_size = width - number_size;
if (align != ALIGN_LEFT)
{
if (align != ALIGN_LEFT) {
CharPtr p = grow_buffer(fill_size);
std::fill(p, p + fill_size, fill);
}
CharPtr result = prepare_int_buffer(
num_digits, subspec, prefix, prefix_size);
if (align == ALIGN_LEFT)
{
if (align == ALIGN_LEFT) {
CharPtr p = grow_buffer(fill_size);
std::fill(p, p + fill_size, fill);
}
return result;
}
unsigned size = prefix_size + num_digits;
if (width <= size)
{
if (width <= size) {
CharPtr p = grow_buffer(size);
std::copy(prefix, prefix + prefix_size, p);
return p + size - 1;
}
CharPtr p = grow_buffer(width);
CharPtr end = p + width;
if (align == ALIGN_LEFT)
{
if (align == ALIGN_LEFT) {
std::copy(prefix, prefix + prefix_size, p);
p += size;
std::fill(p, end, fill);
}
else if (align == ALIGN_CENTER)
{
} else if (align == ALIGN_CENTER) {
p = fill_padding(p, width, size, fill);
std::copy(prefix, prefix + prefix_size, p);
p += size;
}
else
{
if (align == ALIGN_NUMERIC)
{
if (prefix_size != 0)
{
} else {
if (align == ALIGN_NUMERIC) {
if (prefix_size != 0) {
p = std::copy(prefix, prefix + prefix_size, p);
size -= prefix_size;
}
}
else
{
} else {
std::copy(prefix, prefix + prefix_size, end - size);
}
std::fill(p, end - size, fill);
......@@ -2212,103 +1984,77 @@ BasicWriter<Char>::prepare_int_buffer(
template <typename Char>
template <typename T, typename Spec>
void BasicWriter<Char>::write_int(T value, Spec spec)
{
void BasicWriter<Char>::write_int(T value, Spec spec) {
unsigned prefix_size = 0;
typedef typename internal::IntTraits<T>::MainType UnsignedType;
UnsignedType abs_value = value;
char prefix[4] = "";
if (internal::is_negative(value))
{
if (internal::is_negative(value)) {
prefix[0] = '-';
++prefix_size;
abs_value = 0 - abs_value;
}
else if (spec.flag(SIGN_FLAG))
{
} else if (spec.flag(SIGN_FLAG)) {
prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' ';
++prefix_size;
}
switch (spec.type())
{
case 0:
case 'd':
{
switch (spec.type()) {
case 0: case 'd': {
unsigned num_digits = internal::count_digits(abs_value);
CharPtr p = prepare_int_buffer(
num_digits, spec, prefix, prefix_size) + 1 - num_digits;
internal::format_decimal(get(p), abs_value, num_digits);
break;
}
case 'x':
case 'X':
{
case 'x': case 'X': {
UnsignedType n = abs_value;
if (spec.flag(HASH_FLAG))
{
if (spec.flag(HASH_FLAG)) {
prefix[prefix_size++] = '0';
prefix[prefix_size++] = spec.type();
}
unsigned num_digits = 0;
do
{
do {
++num_digits;
}
while ((n >>= 4) != 0);
} while ((n >>= 4) != 0);
Char *p = get(prepare_int_buffer(
num_digits, spec, prefix, prefix_size));
n = abs_value;
const char *digits = spec.type() == 'x' ?
"0123456789abcdef" : "0123456789ABCDEF";
do
{
do {
*p-- = digits[n & 0xf];
}
while ((n >>= 4) != 0);
} while ((n >>= 4) != 0);
break;
}
case 'b':
case 'B':
{
case 'b': case 'B': {
UnsignedType n = abs_value;
if (spec.flag(HASH_FLAG))
{
if (spec.flag(HASH_FLAG)) {
prefix[prefix_size++] = '0';
prefix[prefix_size++] = spec.type();
}
unsigned num_digits = 0;
do
{
do {
++num_digits;
}
while ((n >>= 1) != 0);
} while ((n >>= 1) != 0);
Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size));
n = abs_value;
do
{
do {
*p-- = '0' + (n & 1);
}
while ((n >>= 1) != 0);
} while ((n >>= 1) != 0);
break;
}
case 'o':
{
case 'o': {
UnsignedType n = abs_value;
if (spec.flag(HASH_FLAG))
prefix[prefix_size++] = '0';
unsigned num_digits = 0;
do
{
do {
++num_digits;
}
while ((n >>= 3) != 0);
} while ((n >>= 3) != 0);
Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size));
n = abs_value;
do
{
do {
*p-- = '0' + (n & 7);
}
while ((n >>= 3) != 0);
} while ((n >>= 3) != 0);
break;
}
default:
......@@ -2321,20 +2067,15 @@ void BasicWriter<Char>::write_int(T value, Spec spec)
template <typename Char>
template <typename T>
void BasicWriter<Char>::write_double(
T value, const FormatSpec &spec)
{
T value, const FormatSpec &spec) {
// Check type.
char type = spec.type();
bool upper = false;
switch (type)
{
switch (type) {
case 0:
type = 'g';
break;
case 'e':
case 'f':
case 'g':
case 'a':
case 'e': case 'f': case 'g': case 'a':
break;
case 'F':
#ifdef _MSC_VER
......@@ -2342,9 +2083,7 @@ void BasicWriter<Char>::write_double(
type = 'f';
#endif
// Fall through.
case 'E':
case 'G':
case 'A':
case 'E': case 'G': case 'A':
upper = true;
break;
default:
......@@ -2355,24 +2094,19 @@ void BasicWriter<Char>::write_double(
char sign = 0;
// Use getsign instead of value < 0 because the latter is always
// false for NaN.
if (internal::getsign(static_cast<double>(value)))
{
if (internal::getsign(static_cast<double>(value))) {
sign = '-';
value = -value;
}
else if (spec.flag(SIGN_FLAG))
{
} else if (spec.flag(SIGN_FLAG)) {
sign = spec.flag(PLUS_FLAG) ? '+' : ' ';
}
if (value != value)
{
if (value != value) {
// Format NaN ourselves because sprintf's output is not consistent
// across platforms.
std::size_t nan_size = 4;
const char *nan = upper ? " NAN" : " nan";
if (!sign)
{
if (!sign) {
--nan_size;
++nan;
}
......@@ -2382,14 +2116,12 @@ void BasicWriter<Char>::write_double(
return;
}
if (internal::isinfinity(value))
{
if (internal::isinfinity(value)) {
// Format infinity ourselves because sprintf's output is not consistent
// across platforms.
std::size_t inf_size = 4;
const char *inf = upper ? " INF" : " inf";
if (!sign)
{
if (!sign) {
--inf_size;
++inf;
}
......@@ -2401,8 +2133,7 @@ void BasicWriter<Char>::write_double(
std::size_t offset = buffer_.size();
unsigned width = spec.width();
if (sign)
{
if (sign) {
buffer_.reserve(buffer_.size() + (std::max)(width, 1u));
if (width > 0)
--width;
......@@ -2410,26 +2141,22 @@ void BasicWriter<Char>::write_double(
}
// Build format string.
enum { MAX_FORMAT_SIZE = 10 }; // longest format: %#-*.*Lg
enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
Char format[MAX_FORMAT_SIZE];
Char *format_ptr = format;
*format_ptr++ = '%';
unsigned width_for_sprintf = width;
if (spec.flag(HASH_FLAG))
*format_ptr++ = '#';
if (spec.align() == ALIGN_CENTER)
{
if (spec.align() == ALIGN_CENTER) {
width_for_sprintf = 0;
}
else
{
} else {
if (spec.align() == ALIGN_LEFT)
*format_ptr++ = '-';
if (width != 0)
*format_ptr++ = '*';
}
if (spec.precision() >= 0)
{
if (spec.precision() >= 0) {
*format_ptr++ = '.';
*format_ptr++ = '*';
}
......@@ -2440,15 +2167,13 @@ void BasicWriter<Char>::write_double(
// Format using snprintf.
Char fill = static_cast<Char>(spec.fill());
for (;;)
{
for (;;) {
std::size_t buffer_size = buffer_.capacity() - offset;
#if _MSC_VER
// MSVC's vsnprintf_s doesn't work with zero size, so reserve
// space for at least one extra character to make the size non-zero.
// Note that the buffer's capacity will increase by more than 1.
if (buffer_size == 0)
{
if (buffer_size == 0) {
buffer_.reserve(offset + 1);
buffer_size = buffer_.capacity() - offset;
}
......@@ -2456,33 +2181,26 @@ void BasicWriter<Char>::write_double(
Char *start = &buffer_[offset];
int n = internal::CharTraits<Char>::format_float(
start, buffer_size, format, width_for_sprintf, spec.precision(), value);
if (n >= 0 && offset + n < buffer_.capacity())
{
if (sign)
{
if (n >= 0 && offset + n < buffer_.capacity()) {
if (sign) {
if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
*start != ' ')
{
*start != ' ') {
*(start - 1) = sign;
sign = 0;
}
else
{
} else {
*(start - 1) = fill;
}
++n;
}
if (spec.align() == ALIGN_CENTER &&
spec.width() > static_cast<unsigned>(n))
{
spec.width() > static_cast<unsigned>(n)) {
width = spec.width();
CharPtr p = grow_buffer(width);
std::copy(p, p + n, p + (width - n) / 2);
fill_padding(p, spec.width(), n, fill);
return;
}
if (spec.fill() != ' ' || sign)
{
if (spec.fill() != ' ' || sign) {
while (*start == ' ')
*start++ = fill;
if (sign)
......@@ -2498,64 +2216,65 @@ void BasicWriter<Char>::write_double(
}
/**
\rst
This template provides operations for formatting and writing data into
a character stream. The output is stored in a memory buffer that grows
dynamically.
\rst
This class template provides operations for formatting and writing data
into a character stream. The output is stored in a memory buffer that grows
dynamically.
You can use one of the following typedefs for common character types
and the standard allocator:
You can use one of the following typedefs for common character types
and the standard allocator:
+---------------+-----------------------------------------------+
| Type | Definition |
+===============+===============================================+
| MemoryWriter | BasicWriter<char, std::allocator<char>> |
+---------------+-----------------------------------------------+
| WMemoryWriter | BasicWriter<wchar_t, std::allocator<wchar_t>> |
+---------------+-----------------------------------------------+
+---------------+-----------------------------------------------------+
| Type | Definition |
+===============+=====================================================+
| MemoryWriter | BasicMemoryWriter<char, std::allocator<char>> |
+---------------+-----------------------------------------------------+
| WMemoryWriter | BasicMemoryWriter<wchar_t, std::allocator<wchar_t>> |
+---------------+-----------------------------------------------------+
**Example**::
**Example**::
MemoryWriter out;
out << "The answer is " << 42 << "\n";
out.write("({:+f}, {:+f})", -3.14, 3.14);
MemoryWriter out;
out << "The answer is " << 42 << "\n";
out.write("({:+f}, {:+f})", -3.14, 3.14);
This will write the following output to the ``out`` object:
This will write the following output to the ``out`` object:
.. code-block:: none
.. code-block:: none
The answer is 42
(-3.140000, +3.140000)
The answer is 42
(-3.140000, +3.140000)
The output can be converted to an ``std::string`` with ``out.str()`` or
accessed as a C string with ``out.c_str()``.
\endrst
*/
The output can be converted to an ``std::string`` with ``out.str()`` or
accessed as a C string with ``out.c_str()``.
\endrst
*/
template <typename Char, typename Allocator = std::allocator<Char> >
class BasicMemoryWriter : public BasicWriter<Char>
{
private:
class BasicMemoryWriter : public BasicWriter<Char> {
private:
internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE, Allocator> buffer_;
public:
public:
explicit BasicMemoryWriter(const Allocator& alloc = Allocator())
: BasicWriter<Char>(buffer_), buffer_(alloc) {}
#if FMT_USE_RVALUE_REFERENCES
/**
\rst
Constructs a :class:`fmt::BasicMemoryWriter` object moving the content
of the other object to it.
\endrst
*/
BasicMemoryWriter(BasicMemoryWriter &&other)
: BasicWriter<Char>(buffer_), buffer_(std::move(other.buffer_))
{
: BasicWriter<Char>(buffer_), buffer_(std::move(other.buffer_)) {
}
/**
\rst
Moves the content of the other ``BasicMemoryWriter`` object to this one.
\endrst
*/
BasicMemoryWriter &operator=(BasicMemoryWriter &&other)
{
BasicMemoryWriter &operator=(BasicMemoryWriter &&other) {
buffer_ = std::move(other.buffer_);
return *this;
}
......@@ -2565,16 +2284,63 @@ public:
typedef BasicMemoryWriter<char> MemoryWriter;
typedef BasicMemoryWriter<wchar_t> WMemoryWriter;
/**
\rst
This class template provides operations for formatting and writing data
into a fixed-size array. For writing into a dynamically growing buffer
use :class:`fmt::BasicMemoryWriter`.
Any write method will throw ``std::runtime_error`` if the output doesn't fit
into the array.
You can use one of the following typedefs for common character types:
+--------------+---------------------------+
| Type | Definition |
+==============+===========================+
| ArrayWriter | BasicArrayWriter<char> |
+--------------+---------------------------+
| WArrayWriter | BasicArrayWriter<wchar_t> |
+--------------+---------------------------+
\endrst
*/
template <typename Char>
class BasicArrayWriter : public BasicWriter<Char> {
private:
internal::FixedBuffer<Char> buffer_;
public:
/**
\rst
Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the
given size.
\endrst
*/
BasicArrayWriter(Char *array, std::size_t size)
: BasicWriter<Char>(buffer_), buffer_(array, size) {}
// FIXME: this is temporary undocumented due to a bug in Sphinx
/*
\rst
Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the
size known at compile time.
\endrst
*/
template <std::size_t SIZE>
explicit BasicArrayWriter(Char (&array)[SIZE])
: BasicWriter<Char>(buffer_), buffer_(array, SIZE) {}
};
typedef BasicArrayWriter<char> ArrayWriter;
typedef BasicArrayWriter<wchar_t> WArrayWriter;
// Formats a value.
template <typename Char, typename T>
void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value)
{
void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value) {
std::basic_ostringstream<Char> os;
os << value;
internal::Arg arg;
internal::Value &arg_value = arg;
std::basic_string<Char> str = os.str();
arg_value = internal::MakeValue<Char>(str);
internal::Arg arg = internal::MakeValue<Char>(str);
arg.type = static_cast<internal::Arg::Type>(
internal::MakeValue<Char>::type(str));
format_str = f.format(format_str, arg);
......@@ -2587,12 +2353,11 @@ void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT;
#ifdef _WIN32
/** A Windows error. */
class WindowsError : public SystemError
{
private:
class WindowsError : public SystemError {
private:
void init(int error_code, StringRef format_str, ArgList args);
public:
public:
/**
\rst
Constructs a :class:`fmt::WindowsError` object with the description
......@@ -2621,8 +2386,7 @@ public:
}
\endrst
*/
WindowsError(int error_code, StringRef message)
{
WindowsError(int error_code, StringRef message) {
init(error_code, message, ArgList());
}
FMT_VARIADIC_CTOR(WindowsError, init, int, StringRef)
......@@ -2637,134 +2401,126 @@ void report_windows_error(int error_code, StringRef message) FMT_NOEXCEPT;
enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE };
/**
Formats a string and prints it to stdout using ANSI escape sequences
to specify color (experimental).
Example:
PrintColored(fmt::RED, "Elapsed time: {0:.2f} seconds") << 1.23;
*/
Formats a string and prints it to stdout using ANSI escape sequences
to specify color (experimental).
Example:
PrintColored(fmt::RED, "Elapsed time: {0:.2f} seconds") << 1.23;
*/
void print_colored(Color c, StringRef format, ArgList args);
/**
\rst
Formats arguments and returns the result as a string.
\rst
Formats arguments and returns the result as a string.
**Example**::
**Example**::
std::string message = format("The answer is {}", 42);
\endrst
std::string message = format("The answer is {}", 42);
\endrst
*/
inline std::string format(StringRef format_str, ArgList args)
{
inline std::string format(StringRef format_str, ArgList args) {
MemoryWriter w;
w.write(format_str, args);
return w.str();
}
inline std::wstring format(WStringRef format_str, ArgList args)
{
inline std::wstring format(WStringRef format_str, ArgList args) {
WMemoryWriter w;
w.write(format_str, args);
return w.str();
}
/**
\rst
Prints formatted data to the file *f*.
\rst
Prints formatted data to the file *f*.
**Example**::
**Example**::
print(stderr, "Don't {}!", "panic");
\endrst
*/
print(stderr, "Don't {}!", "panic");
\endrst
*/
void print(std::FILE *f, StringRef format_str, ArgList args);
/**
\rst
Prints formatted data to ``stdout``.
\rst
Prints formatted data to ``stdout``.
**Example**::
**Example**::
print("Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
print("Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
void print(StringRef format_str, ArgList args);
/**
\rst
Prints formatted data to the stream *os*.
\rst
Prints formatted data to the stream *os*.
**Example**::
**Example**::
print(cerr, "Don't {}!", "panic");
\endrst
*/
print(cerr, "Don't {}!", "panic");
\endrst
*/
void print(std::ostream &os, StringRef format_str, ArgList args);
template <typename Char>
void printf(BasicWriter<Char> &w, BasicStringRef<Char> format, ArgList args)
{
void printf(BasicWriter<Char> &w, BasicStringRef<Char> format, ArgList args) {
internal::PrintfFormatter<Char>().format(w, format, args);
}
/**
\rst
Formats arguments and returns the result as a string.
\rst
Formats arguments and returns the result as a string.
**Example**::
**Example**::
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
*/
inline std::string sprintf(StringRef format, ArgList args)
{
inline std::string sprintf(StringRef format, ArgList args) {
MemoryWriter w;
printf(w, format, args);
return w.str();
}
/**
\rst
Prints formatted data to the file *f*.
\rst
Prints formatted data to the file *f*.
**Example**::
**Example**::
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
int fprintf(std::FILE *f, StringRef format, ArgList args);
/**
\rst
Prints formatted data to ``stdout``.
\rst
Prints formatted data to ``stdout``.
**Example**::
**Example**::
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
*/
inline int printf(StringRef format, ArgList args)
{
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
*/
inline int printf(StringRef format, ArgList args) {
return fprintf(stdout, format, args);
}
/**
Fast integer formatter.
*/
class FormatInt
{
private:
Fast integer formatter.
*/
class FormatInt {
private:
// Buffer should be large enough to hold all digits (digits10 + 1),
// a sign and a null character.
enum { BUFFER_SIZE = std::numeric_limits<ULongLong>::digits10 + 3 };
enum {BUFFER_SIZE = std::numeric_limits<ULongLong>::digits10 + 3};
mutable char buffer_[BUFFER_SIZE];
char *str_;
// Formats value in reverse and returns the number of digits.
char *format_decimal(ULongLong value)
{
char *format_decimal(ULongLong value) {
char *buffer_end = buffer_ + BUFFER_SIZE - 1;
while (value >= 100)
{
while (value >= 100) {
// Integer division is slow so do it for a group of two digits instead
// of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison.
......@@ -2773,8 +2529,7 @@ private:
*--buffer_end = internal::Data::DIGITS[index + 1];
*--buffer_end = internal::Data::DIGITS[index];
}
if (value < 10)
{
if (value < 10) {
*--buffer_end = static_cast<char>('0' + value);
return buffer_end;
}
......@@ -2784,8 +2539,7 @@ private:
return buffer_end;
}
void FormatSigned(LongLong value)
{
void FormatSigned(LongLong value) {
ULongLong abs_value = static_cast<ULongLong>(value);
bool negative = value < 0;
if (negative)
......@@ -2795,19 +2549,10 @@ private:
*--str_ = '-';
}
public:
explicit FormatInt(int value)
{
FormatSigned(value);
}
explicit FormatInt(long value)
{
FormatSigned(value);
}
explicit FormatInt(LongLong value)
{
FormatSigned(value);
}
public:
explicit FormatInt(int value) { FormatSigned(value); }
explicit FormatInt(long value) { FormatSigned(value); }
explicit FormatInt(LongLong value) { FormatSigned(value); }
explicit FormatInt(unsigned value) : str_(format_decimal(value)) {}
explicit FormatInt(unsigned long value) : str_(format_decimal(value)) {}
explicit FormatInt(ULongLong value) : str_(format_decimal(value)) {}
......@@ -2815,26 +2560,19 @@ public:
/**
Returns the number of characters written to the output buffer.
*/
std::size_t size() const
{
return buffer_ - str_ + BUFFER_SIZE - 1;
}
std::size_t size() const { return buffer_ - str_ + BUFFER_SIZE - 1; }
/**
Returns a pointer to the output buffer content. No terminating null
character is appended.
*/
const char *data() const
{
return str_;
}
const char *data() const { return str_; }
/**
Returns a pointer to the output buffer content with terminating null
character appended.
*/
const char *c_str() const
{
const char *c_str() const {
buffer_[BUFFER_SIZE - 1] = '\0';
return str_;
}
......@@ -2842,28 +2580,21 @@ public:
/**
Returns the content of the output buffer as an `std::string`.
*/
std::string str() const
{
return std::string(str_, size());
}
std::string str() const { return std::string(str_, size()); }
};
// Formats a decimal integer value writing into buffer and returns
// a pointer to the end of the formatted string. This function doesn't
// write a terminating null character.
template <typename T>
inline void format_decimal(char *&buffer, T value)
{
inline void format_decimal(char *&buffer, T value) {
typename internal::IntTraits<T>::MainType abs_value = value;
if (internal::is_negative(value))
{
if (internal::is_negative(value)) {
*buffer++ = '-';
abs_value = 0 - abs_value;
}
if (abs_value < 100)
{
if (abs_value < 10)
{
if (abs_value < 100) {
if (abs_value < 10) {
*buffer++ = static_cast<char>('0' + abs_value);
return;
}
......@@ -2906,16 +2637,52 @@ inline void format_decimal(char *&buffer, T value)
#define FMT_GET_ARG_NAME(type, index) arg##index
#if FMT_USE_VARIADIC_TEMPLATES
namespace fmt {
namespace internal {
inline void do_set_types(Arg *) {}
template <typename T, typename... Args>
inline void do_set_types(Arg *args, const T &arg, const Args & ... tail) {
args->type = static_cast<Arg::Type>(MakeValue<T>::type(arg));
do_set_types(args + 1, tail...);
}
template <typename... Args>
inline void set_types(Arg *array, const Args & ... args) {
do_set_types(array, args...);
array[sizeof...(Args)].type = Arg::NONE;
}
template <typename... Args>
inline void set_types(Value *, const Args & ...) {
// Do nothing as types are passed separately from values.
}
// Computes the argument array size by adding 1 to N, which is the number of
// arguments, if N is zero, because array of zero size is invalid, or if N
// is greater than ArgList::MAX_PACKED_ARGS to accommodate for an extra
// argument that marks the end of the list.
template <unsigned N>
struct ArgArraySize {
enum { VALUE = N + (N == 0 || N > ArgList::MAX_PACKED_ARGS ? 1 : 0) };
};
}
}
# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \
template <typename... Args> \
ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \
const Args & ... args) { \
using fmt::internal::Value; \
const Value values[fmt::internal::NonZero<sizeof...(Args)>::VALUE] = { \
fmt::internal::MakeValue<Char>(args)... \
namespace internal = fmt::internal; \
typedef typename internal::SelectValueType<sizeof...(Args)>::Type Value; \
Value array[internal::ArgArraySize<sizeof...(Args)>::VALUE] = { \
internal::MakeValue<Char>(args)... \
}; \
call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \
fmt::internal::make_type(args...), values)); \
if (internal::check((sizeof...(Args) > fmt::ArgList::MAX_PACKED_ARGS))) \
set_types(array, args...); \
call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \
fmt::ArgList(internal::make_type(args...), array)); \
}
#else
// Defines a wrapper for a function taking __VA_ARGS__ arguments
......@@ -2924,9 +2691,9 @@ inline void format_decimal(char *&buffer, T value)
template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \
inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \
FMT_GEN(n, FMT_MAKE_ARG)) { \
const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF_##Char)}; \
const fmt::internal::Value values[] = {FMT_GEN(n, FMT_MAKE_REF_##Char)}; \
call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), values)); \
}
# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \
......@@ -2951,40 +2718,39 @@ inline void format_decimal(char *&buffer, T value)
#endif // FMT_USE_VARIADIC_TEMPLATES
/**
\rst
Defines a variadic function with the specified return type, function name
and argument types passed as variable arguments to this macro.
\rst
Defines a variadic function with the specified return type, function name
and argument types passed as variable arguments to this macro.
**Example**::
**Example**::
void print_error(const char *file, int line, const char *format,
fmt::ArgList args) {
fmt::print("{}: {}: ", file, line);
fmt::print(format, args);
}
FMT_VARIADIC(void, print_error, const char *, int, const char *)
void print_error(const char *file, int line, const char *format,
fmt::ArgList args) {
fmt::print("{}: {}: ", file, line);
fmt::print(format, args);
}
FMT_VARIADIC(void, print_error, const char *, int, const char *)
``FMT_VARIADIC`` is used for compatibility with legacy C++ compilers that
don't implement variadic templates. You don't have to use this macro if
you don't need legacy compiler support and can use variadic templates
directly::
``FMT_VARIADIC`` is used for compatibility with legacy C++ compilers that
don't implement variadic templates. You don't have to use this macro if
you don't need legacy compiler support and can use variadic templates
directly::
template <typename... Args>
void print_error(const char *file, int line, const char *format,
const Args & ... args) {
fmt::print("{}: {}: ", file, line);
fmt::print(format, args...);
}
\endrst
*/
template <typename... Args>
void print_error(const char *file, int line, const char *format,
const Args & ... args) {
fmt::print("{}: {}: ", file, line);
fmt::print(format, args...);
}
\endrst
*/
#define FMT_VARIADIC(ReturnType, func, ...) \
FMT_VARIADIC_(char, ReturnType, func, return func, __VA_ARGS__)
#define FMT_VARIADIC_W(ReturnType, func, ...) \
FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__)
namespace fmt
{
namespace fmt {
FMT_VARIADIC(std::string, format, StringRef)
FMT_VARIADIC_W(std::wstring, format, WStringRef)
FMT_VARIADIC(void, print, StringRef)
......@@ -3004,6 +2770,7 @@ FMT_VARIADIC(int, fprintf, std::FILE *, StringRef)
#ifdef __clang__
# pragma clang diagnostic pop
#endif
#ifdef FMT_HEADER_ONLY
# include "format.cc"
#endif
......
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