Commit 1c13f5d7 authored by gabime's avatar gabime

Updated cppformat to fix issue #110

parent 83d47aa6
/*
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.
*/
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"
......@@ -35,11 +35,18 @@
#include <cmath>
#include <cstdarg>
#ifdef _WIN32
# ifdef __MINGW32__
#if defined(_WIN32) && defined(__MINGW32__)
# include <cstring>
# endif
#endif
#if FMT_USE_WINDOWS_H
# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
# include <windows.h>
# else
# define NOMINMAX
# include <windows.h>
# undef NOMINMAX
# endif
#endif
using fmt::internal::Arg;
......@@ -88,13 +95,14 @@ using fmt::internal::Arg;
// 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::Null<> strerror_r(int, char *, ...) {
return fmt::internal::Null<>();
}
static inline fmt::internal::None<> strerror_s(char *, std::size_t, ...) {
return fmt::internal::None<>();
static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
return fmt::internal::Null<>();
}
namespace fmt {
namespace {
#ifndef _MSC_VER
......@@ -125,6 +133,9 @@ struct IntChecker {
unsigned max = INT_MAX;
return value <= max;
}
static bool fits_in_int(bool) {
return true;
}
};
template <>
......@@ -137,7 +148,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.
......@@ -149,8 +160,8 @@ 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 {
assert(buffer != 0 && buffer_size != 0);
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT{
FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer");
class StrError {
private:
......@@ -177,7 +188,7 @@ int safe_strerror(
}
// Handle the case when strerror_r is not available.
int handle(fmt::internal::None<>) {
int handle(fmt::internal::Null<>) {
return fallback(strerror_s(buffer_, buffer_size_, error_code_));
}
......@@ -189,7 +200,7 @@ int safe_strerror(
}
// Fallback to strerror if strerror_r and strerror_s are not available.
int fallback(fmt::internal::None<>) {
int fallback(fmt::internal::Null<>) {
errno = 0;
buffer_ = strerror(error_code_);
return errno;
......@@ -199,13 +210,16 @@ int safe_strerror(
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_)); }
int run() {
strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r.
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.
......@@ -223,7 +237,7 @@ void format_error_code(fmt::Writer &out, int error_code,
}
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
......@@ -234,9 +248,11 @@ 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.
......@@ -259,6 +275,11 @@ int parse_nonnegative_int(const Char *&s) {
return value;
}
template <typename Char>
inline bool is_name_start(Char c) {
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
}
inline void require_numeric_argument(const Arg &arg, char spec) {
if (arg.type > Arg::LAST_NUMERIC_TYPE) {
std::string message =
......@@ -281,12 +302,12 @@ 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) {}
void report_unhandled_arg() {
......@@ -309,7 +330,7 @@ class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
class PrecisionHandler :
public fmt::internal::ArgVisitor<PrecisionHandler, int> {
public:
public:
void report_unhandled_arg() {
FMT_THROW(fmt::FormatError("precision is not integer"));
}
......@@ -325,13 +346,13 @@ class PrecisionHandler :
// 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) {}
......@@ -344,17 +365,20 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
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);
......@@ -365,12 +389,12 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
// 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>
......@@ -379,24 +403,152 @@ class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
arg_.int_value = static_cast<char>(value);
}
};
} // namespace
namespace internal {
template <typename Impl, typename Char>
class BasicArgFormatter : public ArgVisitor<Impl, void> {
private:
BasicWriter<Char> &writer_;
FormatSpec &spec_;
FMT_DISALLOW_COPY_AND_ASSIGN(BasicArgFormatter);
protected:
BasicWriter<Char> &writer() {
return writer_;
}
const FormatSpec &spec() const {
return spec_;
}
public:
BasicArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
: writer_(w), spec_(s) {}
template <typename T>
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_bool(bool value) {
if (spec_.type_) {
writer_.write_int(value, spec_);
return;
}
const char *str_value = value ? "true" : "false";
Arg::StringValue<char> str = { str_value, strlen(str_value) };
writer_.write_str(str, spec_);
}
// This function template is used to prevent compile errors when handling
// incompatible string arguments, e.g. handling a wide string in a narrow
// string formatter.
void visit_char(int value) {
if (spec_.type_ && spec_.type_ != 'c') {
spec_.flags_ |= CHAR_FLAG;
writer_.write_int(value, spec_);
return;
}
if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
FMT_THROW(FormatError("invalid format specifier for char"));
typedef typename BasicWriter<Char>::CharPtr CharPtr;
Char fill = internal::CharTraits<Char>::cast(spec_.fill());
CharPtr out = CharPtr();
if (spec_.width_ > 1) {
out = writer_.grow_buffer(spec_.width_);
if (spec_.align_ == ALIGN_RIGHT) {
std::fill_n(out, spec_.width_ - 1, fill);
out += spec_.width_ - 1;
}
else if (spec_.align_ == ALIGN_CENTER) {
out = writer_.fill_padding(out, spec_.width_, 1, fill);
}
else {
std::fill_n(out + 1, spec_.width_ - 1, fill);
}
}
else {
out = writer_.grow_buffer(1);
}
*out = internal::CharTraits<Char>::cast(value);
}
void visit_string(Arg::StringValue<char> value) {
writer_.write_str(value, spec_);
}
using ArgVisitor<Impl, void>::visit_wstring;
void visit_wstring(Arg::StringValue<Char> value) {
writer_.write_str(value, spec_);
}
void visit_pointer(const void *value) {
if (spec_.type_ && spec_.type_ != 'p')
report_unknown_type(spec_.type_, "pointer");
spec_.flags_ = HASH_FLAG;
spec_.type_ = 'x';
writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
}
};
// An argument formatter.
template <typename Char>
Arg::StringValue<Char> ignore_incompatible_str(Arg::StringValue<wchar_t>);
class ArgFormatter : public BasicArgFormatter<ArgFormatter<Char>, Char> {
private:
BasicFormatter<Char> &formatter_;
const Char *format_;
template <>
inline Arg::StringValue<char> ignore_incompatible_str(
Arg::StringValue<wchar_t>) { return Arg::StringValue<char>(); }
public:
ArgFormatter(BasicFormatter<Char> &f, FormatSpec &s, const Char *fmt)
: BasicArgFormatter<ArgFormatter<Char>, Char>(f.writer(), s),
formatter_(f), format_(fmt) {}
template <>
inline Arg::StringValue<wchar_t> ignore_incompatible_str(
Arg::StringValue<wchar_t> s) { return s; }
} // namespace
void visit_custom(Arg::CustomValue c) {
c.format(&formatter_, c.value, &format_);
}
};
template <typename Char>
class PrintfArgFormatter :
public BasicArgFormatter<PrintfArgFormatter<Char>, Char> {
public:
PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
: BasicArgFormatter<PrintfArgFormatter<Char>, Char>(w, s) {}
void visit_char(int value) {
const FormatSpec &spec = this->spec();
BasicWriter<Char> &writer = this->writer();
if (spec.type_ && spec.type_ != 'c')
writer.write_int(value, spec);
typedef typename BasicWriter<Char>::CharPtr CharPtr;
CharPtr out = CharPtr();
if (spec.width_ > 1) {
Char fill = ' ';
out = writer.grow_buffer(spec.width_);
if (spec.align_ != ALIGN_LEFT) {
std::fill_n(out, spec.width_ - 1, fill);
out += spec.width_ - 1;
}
else {
std::fill_n(out + 1, spec.width_ - 1, fill);
}
}
else {
out = writer.grow_buffer(1);
}
*out = static_cast<Char>(value);
}
};
} // namespace internal
} // namespace fmt
FMT_FUNC void fmt::SystemError::init(
int err_code, StringRef format_str, ArgList args) {
int err_code, CStringRef format_str, ArgList args) {
error_code_ = err_code;
MemoryWriter w;
internal::format_system_error(w, err_code, format(format_str, args));
......@@ -477,19 +629,20 @@ FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
static_cast<unsigned>(code), type)));
}
#ifdef _WIN32
#if FMT_USE_WINDOWS_H
FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
int length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s.size(), 0, 0);
static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
if (length == 0)
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
buffer_.resize(length);
buffer_.resize(length + 1);
length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s.size(), &buffer_[0], length);
if (length == 0)
FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
buffer_[length] = 0;
}
FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
......@@ -500,19 +653,20 @@ FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
}
FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0);
int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s.size(), 0, 0, 0, 0);
if (length == 0)
return GetLastError();
buffer_.resize(length);
buffer_.resize(length + 1);
length = WideCharToMultiByte(
CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0);
CP_UTF8, 0, s.data(), s.size(), &buffer_[0], length, 0, 0);
if (length == 0)
return GetLastError();
buffer_[length] = 0;
return 0;
}
FMT_FUNC void fmt::WindowsError::init(
int err_code, StringRef format_str, ArgList args) {
int err_code, CStringRef format_str, ArgList args) {
error_code_ = err_code;
MemoryWriter w;
internal::format_windows_error(w, err_code, format(format_str, args));
......@@ -520,44 +674,24 @@ FMT_FUNC void fmt::WindowsError::init(
base = std::runtime_error(w.str());
}
#endif
FMT_FUNC void fmt::internal::format_system_error(
fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT {
FMT_TRY {
MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
buffer.resize(INLINE_BUFFER_SIZE);
for (;;) {
char *system_message = &buffer[0];
int result = safe_strerror(error_code, system_message, buffer.size());
if (result == 0) {
out << message << ": " << system_message;
return;
}
if (result != ERANGE)
break; // Can't get error message, report error code instead.
buffer.resize(buffer.size() * 2);
}
} FMT_CATCH(...) {}
format_error_code(out, error_code, message);
}
#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,
......@@ -572,81 +706,76 @@ FMT_FUNC void fmt::internal::format_windows_error(
} FMT_CATCH(...) {}
format_error_code(out, error_code, message);
}
#endif
// An argument formatter.
template <typename Char>
class fmt::internal::ArgFormatter :
public fmt::internal::ArgVisitor<fmt::internal::ArgFormatter<Char>, void> {
private:
fmt::BasicFormatter<Char> &formatter_;
fmt::BasicWriter<Char> &writer_;
fmt::FormatSpec &spec_;
const Char *format_;
#endif // FMT_USE_WINDOWS_H
FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatter);
public:
ArgFormatter(
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_); }
template <typename T>
void visit_any_double(T value) { writer_.write_double(value, spec_); }
void visit_char(int value) {
if (spec_.type_ && spec_.type_ != 'c') {
spec_.flags_ |= CHAR_FLAG;
writer_.write_int(value, spec_);
FMT_FUNC void fmt::internal::format_system_error(
fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT{
FMT_TRY{
MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
buffer.resize(INLINE_BUFFER_SIZE);
for (;;) {
char *system_message = &buffer[0];
int result = safe_strerror(error_code, system_message, buffer.size());
if (result == 0) {
out << message << ": " << system_message;
return;
}
if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
FMT_THROW(FormatError("invalid format specifier for char"));
typedef typename fmt::BasicWriter<Char>::CharPtr CharPtr;
Char fill = static_cast<Char>(spec_.fill());
if (spec_.precision_ == 0) {
std::fill_n(writer_.grow_buffer(spec_.width_), spec_.width_, fill);
return;
if (result != ERANGE)
break; // Can't get error message, report error code instead.
buffer.resize(buffer.size() * 2);
}
CharPtr out = CharPtr();
if (spec_.width_ > 1) {
out = writer_.grow_buffer(spec_.width_);
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) {
out = writer_.fill_padding(out, spec_.width_, 1, fill);
} else {
std::fill_n(out + 1, spec_.width_ - 1, fill);
} FMT_CATCH(...) {}
format_error_code(out, error_code, message);
}
template <typename Char>
void fmt::internal::ArgMap<Char>::init(const ArgList &args) {
if (!map_.empty())
return;
typedef internal::NamedArg<Char> NamedArg;
const NamedArg *named_arg = 0;
bool use_values =
args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
if (use_values) {
for (unsigned i = 0;/*nothing*/; ++i) {
internal::Arg::Type arg_type = args.type(i);
switch (arg_type) {
case internal::Arg::NONE:
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
map_.insert(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/
;
}
} else {
out = writer_.grow_buffer(1);
}
*out = static_cast<Char>(value);
return;
}
void visit_string(Arg::StringValue<char> value) {
writer_.write_str(value, spec_);
for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
internal::Arg::Type arg_type = args.type(i);
if (arg_type == internal::Arg::NAMED_ARG) {
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.insert(Pair(named_arg->name, *named_arg));
}
void visit_wstring(Arg::StringValue<wchar_t> value) {
writer_.write_str(ignore_incompatible_str<Char>(value), spec_);
}
void visit_pointer(const void *value) {
if (spec_.type_ && spec_.type_ != 'p')
fmt::internal::report_unknown_type(spec_.type_, "pointer");
spec_.flags_ = fmt::HASH_FLAG;
spec_.type_ = 'x';
writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
switch (args.args_[i].type) {
case internal::Arg::NONE:
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.insert(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/
;
}
void visit_custom(Arg::CustomValue c) {
c.format(&formatter_, c.value, &format_);
}
};
}
template <typename Char>
void fmt::internal::FixedBuffer<Char>::grow(std::size_t) {
......@@ -675,6 +804,19 @@ void fmt::BasicWriter<Char>::write_str(
write_str(str_value, str_size, spec);
}
template <typename Char>
inline Arg fmt::BasicFormatter<Char>::get_arg(
BasicStringRef<Char> arg_name, const char *&error) {
if (check_no_auto_index(error)) {
map_.init(args());
const Arg *arg = map_.find(arg_name);
if (arg)
return *arg;
error = "argument not found";
}
return Arg();
}
template <typename Char>
inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
const char *error = 0;
......@@ -687,11 +829,34 @@ inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
return arg;
}
template <typename Char>
inline Arg fmt::BasicFormatter<Char>::parse_arg_name(const Char *&s) {
assert(is_name_start(*s));
const Char *start = s;
Char c;
do {
c = *++s;
} while (is_name_start(c) || ('0' <= c && c <= '9'));
const char *error = 0;
Arg arg = get_arg(fmt::BasicStringRef<Char>(start, s - start), error);
if (error)
FMT_THROW(fmt::FormatError(error));
return arg;
}
FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
unsigned arg_index, const char *&error) {
Arg arg = args_[arg_index];
if (arg.type == Arg::NONE)
switch (arg.type) {
case Arg::NONE:
error = "argument index out of range";
break;
case Arg::NAMED_ARG:
arg = *static_cast<const internal::Arg*>(arg.pointer);
default:
/*nothing*/
;
}
return arg;
}
......@@ -702,14 +867,19 @@ inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
return Arg();
}
inline bool fmt::internal::FormatterBase::check_no_auto_index(
const char *&error) {
if (next_arg_index_ > 0) {
error = "cannot switch from automatic to manual argument indexing";
return false;
}
next_arg_index_ = -1;
return true;
}
inline Arg fmt::internal::FormatterBase::get_arg(
unsigned arg_index, const char *&error) {
if (next_arg_index_ <= 0) {
next_arg_index_ = -1;
return do_get_arg(arg_index, error);
}
error = "cannot switch from automatic to manual argument indexing";
return Arg();
return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg();
}
template <typename Char>
......@@ -763,7 +933,8 @@ 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) {
......@@ -778,7 +949,8 @@ 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));
}
......@@ -787,7 +959,7 @@ unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
template <typename Char>
void fmt::internal::PrintfFormatter<Char>::format(
BasicWriter<Char> &writer, BasicStringRef<Char> format_str,
BasicWriter<Char> &writer, BasicCStringRef<Char> format_str,
const ArgList &args) {
const Char *start = format_str.c_str();
set_args(args);
......@@ -813,7 +985,8 @@ 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));
}
......@@ -868,7 +1041,8 @@ 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':
......@@ -881,73 +1055,7 @@ void fmt::internal::PrintfFormatter<Char>::format(
start = s;
// Format argument.
switch (arg.type) {
case Arg::INT:
writer.write_int(arg.int_value, spec);
break;
case Arg::UINT:
writer.write_int(arg.uint_value, spec);
break;
case Arg::LONG_LONG:
writer.write_int(arg.long_long_value, spec);
break;
case Arg::ULONG_LONG:
writer.write_int(arg.ulong_long_value, spec);
break;
case Arg::CHAR: {
if (spec.type_ && spec.type_ != 'c')
writer.write_int(arg.int_value, spec);
typedef typename BasicWriter<Char>::CharPtr CharPtr;
CharPtr out = CharPtr();
if (spec.width_ > 1) {
Char fill = ' ';
out = writer.grow_buffer(spec.width_);
if (spec.align_ != ALIGN_LEFT) {
std::fill_n(out, spec.width_ - 1, fill);
out += spec.width_ - 1;
} else {
std::fill_n(out + 1, spec.width_ - 1, fill);
}
} else {
out = writer.grow_buffer(1);
}
*out = static_cast<Char>(arg.int_value);
break;
}
case Arg::DOUBLE:
writer.write_double(arg.double_value, spec);
break;
case Arg::LONG_DOUBLE:
writer.write_double(arg.long_double_value, spec);
break;
case Arg::CSTRING:
arg.string.size = 0;
writer.write_str(arg.string, spec);
break;
case Arg::STRING:
writer.write_str(arg.string, spec);
break;
case Arg::WSTRING:
writer.write_str(ignore_incompatible_str<Char>(arg.wstring), spec);
break;
case Arg::POINTER:
if (spec.type_ && spec.type_ != 'p')
internal::report_unknown_type(spec.type_, "pointer");
spec.flags_= HASH_FLAG;
spec.type_ = 'x';
writer.write_int(reinterpret_cast<uintptr_t>(arg.pointer), spec);
break;
case Arg::CUSTOM: {
if (spec.type_)
internal::report_unknown_type(spec.type_, "object");
const void *str_format = "s";
arg.custom.format(&writer, arg.custom.value, &str_format);
break;
}
default:
assert(false);
break;
}
internal::PrintfArgFormatter<Char>(writer, spec).visit(arg);
}
write(writer, start, s);
}
......@@ -989,7 +1097,8 @@ 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;
......@@ -1019,17 +1128,49 @@ const Char *fmt::BasicFormatter<Char>::format(
++s;
}
// Parse width and zero flag.
if ('0' <= *s && *s <= '9') {
// Parse zero flag.
if (*s == '0') {
require_numeric_argument(arg, '0');
spec.align_ = ALIGN_NUMERIC;
spec.fill_ = '0';
++s;
}
// Zero may be parsed again as a part of the width, but it is simpler
// and more efficient than checking if the next char is a digit.
// Parse width.
if ('0' <= *s && *s <= '9') {
spec.width_ = parse_nonnegative_int(s);
}
else if (*s == '{') {
++s;
Arg width_arg = is_name_start(*s) ?
parse_arg_name(s) : parse_arg_index(s);
if (*s++ != '}')
FMT_THROW(FormatError("invalid format string"));
ULongLong value = 0;
switch (width_arg.type) {
case Arg::INT:
if (width_arg.int_value < 0)
FMT_THROW(FormatError("negative width"));
value = width_arg.int_value;
break;
case Arg::UINT:
value = width_arg.uint_value;
break;
case Arg::LONG_LONG:
if (width_arg.long_long_value < 0)
FMT_THROW(FormatError("negative width"));
value = width_arg.long_long_value;
break;
case Arg::ULONG_LONG:
value = width_arg.ulong_long_value;
break;
default:
FMT_THROW(FormatError("width is not integer"));
}
if (value > INT_MAX)
FMT_THROW(FormatError("number is too big"));
spec.width_ = static_cast<int>(value);
}
// Parse precision.
if (*s == '.') {
......@@ -1037,9 +1178,11 @@ 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);
Arg precision_arg =
is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
if (*s++ != '}')
FMT_THROW(FormatError("invalid format string"));
ULongLong value = 0;
......@@ -1066,10 +1209,11 @@ 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) {
if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) {
FMT_THROW(FormatError(
fmt::format("precision not allowed in {} format specifier",
arg.type == Arg::POINTER ? "pointer" : "integer")));
......@@ -1092,7 +1236,7 @@ const Char *fmt::BasicFormatter<Char>::format(
template <typename Char>
void fmt::BasicFormatter<Char>::format(
BasicStringRef<Char> format_str, const ArgList &args) {
BasicCStringRef<Char> format_str, const ArgList &args) {
const Char *s = start_ = format_str.c_str();
set_args(args);
while (*s) {
......@@ -1106,41 +1250,41 @@ void fmt::BasicFormatter<Char>::format(
if (c == '}')
FMT_THROW(FormatError("unmatched '}' in format string"));
write(writer_, start_, s - 1);
Arg arg = parse_arg_index(s);
Arg arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);
s = format(s, arg);
}
write(writer_, start_, s);
}
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
#if FMT_USE_WINDOWS_H
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
FMT_FUNC void fmt::print(std::FILE *f, StringRef format_str, ArgList args) {
FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) {
MemoryWriter w;
w.write(format_str, args);
std::fwrite(w.data(), 1, w.size(), f);
}
FMT_FUNC void fmt::print(StringRef format_str, ArgList args) {
FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
print(stdout, format_str, args);
}
FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args) {
FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args) {
MemoryWriter w;
w.write(format_str, args);
os.write(w.data(), w.size());
}
FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) {
FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
char escape[] = "\x1b[30m";
escape[3] = '0' + static_cast<char>(c);
std::fputs(escape, stdout);
......@@ -1148,7 +1292,7 @@ FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) {
std::fputs(RESET_COLOR, stdout);
}
FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
MemoryWriter w;
printf(w, format, args);
std::size_t size = w.size();
......@@ -1157,6 +1301,8 @@ FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
#ifndef FMT_HEADER_ONLY
template struct fmt::internal::BasicData<void>;
// Explicit instantiations for char.
template void fmt::internal::FixedBuffer<char>::grow(std::size_t);
......@@ -1165,10 +1311,10 @@ template const char *fmt::BasicFormatter<char>::format(
const char *&format_str, const fmt::internal::Arg &arg);
template void fmt::BasicFormatter<char>::format(
BasicStringRef<char> format, const ArgList &args);
CStringRef format, const ArgList &args);
template void fmt::internal::PrintfFormatter<char>::format(
BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
BasicWriter<char> &writer, CStringRef format, const ArgList &args);
template int fmt::internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format,
......@@ -1186,10 +1332,10 @@ template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
const wchar_t *&format_str, const fmt::internal::Arg &arg);
template void fmt::BasicFormatter<wchar_t>::format(
BasicStringRef<wchar_t> format, const ArgList &args);
BasicCStringRef<wchar_t> format, const ArgList &args);
template void fmt::internal::PrintfFormatter<wchar_t>::format(
BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
BasicWriter<wchar_t> &writer, WCStringRef format,
const ArgList &args);
template int fmt::internal::CharTraits<wchar_t>::format_float(
......
/*
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.
*/
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_
......@@ -41,6 +41,7 @@
#include <stdexcept>
#include <string>
#include <sstream>
#include <map>
#if _SECURE_SCL
# include <iterator>
......@@ -154,26 +155,34 @@ inline uint32_t clzll(uint64_t x) {
#endif
// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature).
#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
#ifndef FMT_NOEXCEPT
# if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11)
# define FMT_NOEXCEPT noexcept
#else
# else
# define FMT_NOEXCEPT throw()
# endif
#endif
// A macro to disallow the copy constructor and operator= functions
// This should be used in the private: declarations for a class
#if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \
(FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800
# define FMT_DELETED_OR_UNDEFINED = delete
# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&) = delete; \
TypeName& operator=(const TypeName&) = delete
#else
# define FMT_DELETED_OR_UNDEFINED
# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
TypeName& operator=(const TypeName&)
#endif
#ifndef FMT_ASSERT
# define FMT_ASSERT(condition, message) assert((condition) && message)
#endif
namespace fmt {
// Fix the warning about long long on older versions of GCC
......@@ -198,71 +207,74 @@ 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:
private:
const Char *data_;
std::size_t size_;
public:
/**
Constructs a string reference object from a C string and a size.
*/
public:
/** Constructs a string reference object from a C string and a size. */
BasicStringRef(const Char *s, std::size_t size) : data_(s), size_(size) {}
/**
\rst
Constructs a string reference object from a C string computing
the size with ``std::char_traits<Char>::length``.
\endrst
*/
BasicStringRef(const Char *s)
: data_(s), size_(std::char_traits<Char>::length(s)) {}
/**
Constructs a string reference from an `std::string` object.
\rst
Constructs a string reference from an ``std::string`` object.
\endrst
*/
BasicStringRef(const std::basic_string<Char> &s)
: data_(s.c_str()), size_(s.size()) {}
/**
Converts a string reference to an `std::string` object.
\rst
Converts a string reference to an ``std::string`` object.
\endrst
*/
operator std::basic_string<Char>() const {
return std::basic_string<Char>(data_, size());
std::basic_string<Char> to_string() const {
return std::basic_string<Char>(data_, size_);
}
/**
Returns the pointer to a C string.
*/
const Char *c_str() const { return data_; }
/** Returns the pointer to a C string. */
const Char *data() const {
return data_;
}
/**
Returns the string size.
*/
std::size_t size() const { return size_; }
/** Returns the string size. */
std::size_t size() const {
return size_;
}
friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) {
return lhs.data_ == rhs.data_;
......@@ -270,17 +282,72 @@ class BasicStringRef {
friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) {
return lhs.data_ != rhs.data_;
}
friend bool operator<(BasicStringRef lhs, BasicStringRef rhs) {
return std::lexicographical_compare(
lhs.data_, lhs.data_ + lhs.size_, rhs.data_, rhs.data_ + rhs.size_);
}
};
typedef BasicStringRef<char> StringRef;
typedef BasicStringRef<wchar_t> WStringRef;
/**
\rst
A reference to a null terminated string. It can be constructed from a C
string or ``std::string``.
You can use one of the following typedefs for common character types:
+-------------+--------------------------+
| Type | Definition |
+=============+==========================+
| CStringRef | BasicCStringRef<char> |
+-------------+--------------------------+
| WCStringRef | BasicCStringRef<wchar_t> |
+-------------+--------------------------+
This class is most useful as a parameter type to allow passing
different types of strings to a function, for example::
template <typename... Args>
std::string format(CStringRef format_str, const Args & ... args);
format("{}", 42);
format(std::string("{}"), 42);
\endrst
*/
template <typename Char>
class BasicCStringRef {
private:
const Char *data_;
public:
/** Constructs a string reference object from a C string. */
BasicCStringRef(const Char *s) : data_(s) {}
/**
\rst
Constructs a string reference from an ``std::string`` object.
\endrst
*/
BasicCStringRef(const std::basic_string<Char> &s) : data_(s.c_str()) {}
/** Returns the pointer to a C string. */
const Char *c_str() const {
return data_;
}
};
typedef BasicCStringRef<char> CStringRef;
typedef BasicCStringRef<wchar_t> WCStringRef;
/**
A formatting error such as invalid format string.
A formatting error such as invalid format string.
*/
class FormatError : public std::runtime_error {
public:
explicit FormatError(StringRef message)
public:
explicit FormatError(CStringRef message)
: std::runtime_error(message.c_str()) {}
};
......@@ -297,17 +364,23 @@ inline stdext::checked_array_iterator<T*> make_ptr(T *ptr, std::size_t 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 supporting a subset of ``std::vector``'s operations. */
/**
\rst
A buffer supporting a subset of ``std::vector``'s operations.
\endrst
*/
template <typename T>
class Buffer {
private:
private:
FMT_DISALLOW_COPY_AND_ASSIGN(Buffer);
protected:
protected:
T *ptr_;
std::size_t size_;
std::size_t capacity_;
......@@ -316,19 +389,25 @@ class Buffer {
: ptr_(ptr), size_(0), capacity_(capacity) {}
/**
\rst
Increases the buffer capacity to hold at least *size* elements updating
``ptr_`` and ``capacity_``.
\endrst
*/
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_; }
std::size_t size() const {
return size_;
}
/** Returns the capacity of this buffer. */
std::size_t capacity() const { return capacity_; }
std::size_t capacity() const {
return capacity_;
}
/**
Resizes the buffer. If T is a POD type new elements may not be initialized.
......@@ -339,13 +418,17 @@ class Buffer {
size_ = new_size;
}
/** Reserves space to store at least *capacity* elements. */
/**
\rst
Reserves space to store at least *capacity* elements.
\endrst
*/
void reserve(std::size_t capacity) {
if (capacity > capacity_)
grow(capacity);
}
void clear() FMT_NOEXCEPT { size_ = 0; }
void clear() FMT_NOEXCEPT{ size_ = 0; }
void push_back(const T &value) {
if (size_ == capacity_)
......@@ -354,14 +437,20 @@ class Buffer {
}
/** Appends data to the end of the buffer. */
void append(const T *begin, const T *end);
template <typename U>
void append(const U *begin, const U *end);
T &operator[](std::size_t index) { return ptr_[index]; }
const T &operator[](std::size_t index) const { return ptr_[index]; }
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) {
template <typename U>
void Buffer<T>::append(const U *begin, const U *end) {
std::ptrdiff_t num_elements = end - begin;
if (size_ + num_elements > capacity_)
grow(size_ + num_elements);
......@@ -375,7 +464,7 @@ namespace internal {
// the object itself.
template <typename T, std::size_t SIZE, typename Allocator = std::allocator<T> >
class MemoryBuffer : private Allocator, public Buffer<T> {
private:
private:
T data_[SIZE];
// Free memory allocated by the buffer.
......@@ -383,16 +472,18 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
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) {
Allocator &this_alloc = *this, &other_alloc = other;
......@@ -403,7 +494,8 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
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.
......@@ -411,7 +503,7 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
}
}
public:
public:
MemoryBuffer(MemoryBuffer &&other) {
move(other);
}
......@@ -425,7 +517,9 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
#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>
......@@ -450,10 +544,10 @@ void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size) {
// A fixed-size buffer.
template <typename Char>
class FixedBuffer : public fmt::Buffer<Char> {
public:
public:
FixedBuffer(Char *array, std::size_t size) : fmt::Buffer<Char>(array, size) {}
protected:
protected:
void grow(std::size_t size);
};
......@@ -471,11 +565,19 @@ 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) {
......@@ -486,18 +588,25 @@ 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:
public:
#if _SECURE_SCL
typedef stdext::checked_array_iterator<Char*> CharPtr;
#else
typedef Char *CharPtr;
#endif
static Char cast(wchar_t value) {
return static_cast<Char>(value);
}
};
template <typename Char>
......@@ -505,12 +614,14 @@ class CharTraits;
template <>
class CharTraits<char> : public BasicCharTraits<char> {
private:
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>
......@@ -520,9 +631,13 @@ 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; }
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,
......@@ -533,13 +648,17 @@ class CharTraits<wchar_t> : public BasicCharTraits<wchar_t> {
template <bool IsSigned>
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> {
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.
......@@ -551,10 +670,14 @@ inline bool is_negative(T 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 {
......@@ -566,7 +689,9 @@ 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 <> \
......@@ -658,56 +783,71 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
buffer[0] = Data::DIGITS[index];
}
#ifdef _WIN32
#ifndef _WIN32
# define FMT_USE_WINDOWS_H 0
#elif !defined(FMT_USE_WINDOWS_H)
# define FMT_USE_WINDOWS_H 1
#endif
// Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h.
// All the functionality that relies on it will be disabled too.
#if FMT_USE_WINDOWS_H
// A converter from UTF-8 to UTF-16.
// It is only provided for Windows since other systems support UTF-8 natively.
class UTF8ToUTF16 {
private:
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:
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
// in case of memory allocation error.
int convert(WStringRef s);
};
#endif
void format_system_error(fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT;
#ifdef _WIN32
void format_windows_error(fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT;
#endif
// Computes max(N, 1) at compile time. It is used to avoid errors about
// allocating an array of 0 size.
template <unsigned N>
struct NonZero {
enum { VALUE = N > 0 ? N : 1 };
};
void format_system_error(fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT;
// A formatting argument value.
struct Value {
......@@ -717,7 +857,7 @@ struct Value {
std::size_t size;
};
typedef void (*FormatFunc)(
typedef void(*FormatFunc)(
void *formatter, const void *arg, void *format_str_ptr);
struct CustomValue {
......@@ -741,9 +881,9 @@ struct Value {
};
enum Type {
NONE,
NONE, NAMED_ARG,
// Integer types should go first,
INT, UINT, LONG_LONG, ULONG_LONG, CHAR, LAST_INTEGER_TYPE = CHAR,
INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR,
// followed by floating-point types.
DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE,
CSTRING, STRING, WSTRING, POINTER, CUSTOM
......@@ -756,26 +896,29 @@ struct Arg : Value {
Type type;
};
template <typename Char>
struct NamedArg;
template <typename T = void>
struct None {};
struct Null {};
// A helper class template to enable or disable overloads taking wide
// characters and strings in MakeValue.
template <typename T, typename Char>
struct WCharHelper {
typedef None<T> Supported;
typedef Null<T> Supported;
typedef T Unsupported;
};
template <typename T>
struct WCharHelper<T, wchar_t> {
typedef T Supported;
typedef None<T> Unsupported;
typedef Null<T> Unsupported;
};
template <typename T>
class IsConvertibleToInt {
private:
private:
typedef char yes[1];
typedef char no[2];
......@@ -784,7 +927,7 @@ class IsConvertibleToInt {
static yes &check(fmt::ULongLong);
static no &check(...);
public:
public:
enum { value = (sizeof(check(get())) == sizeof(yes)) };
};
......@@ -804,22 +947,30 @@ template<bool B, class T = void>
struct EnableIf {};
template<class T>
struct EnableIf<true, T> { typedef T type; };
struct EnableIf<true, T> {
typedef T type;
};
template<bool B, class T, class F>
struct Conditional { typedef T type; };
struct Conditional {
typedef T type;
};
template<class T, class F>
struct Conditional<false, T, F> { typedef F type; };
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; }
inline bool check(bool value) {
return value;
}
// Makes an Arg object from any type.
template <typename Char>
class MakeValue : public Arg {
private:
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
......@@ -841,12 +992,12 @@ class MakeValue : public Arg {
MakeValue(typename WCharHelper<WStringRef, Char>::Unsupported);
void set_string(StringRef str) {
string.value = str.c_str();
string.value = str.data();
string.size = str.size();
}
void set_string(WStringRef str) {
wstring.value = str.c_str();
wstring.value = str.data();
wstring.size = str.size();
}
......@@ -859,14 +1010,17 @@ class MakeValue : public Arg {
*static_cast<const T*>(arg));
}
public:
public:
MakeValue() {}
#define FMT_MAKE_VALUE(Type, field, TYPE) \
MakeValue(Type value) { field = value; } \
#define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \
MakeValue(Type value) { field = rhs; } \
static uint64_t type(Type) { return Arg::TYPE; }
FMT_MAKE_VALUE(bool, int_value, INT)
#define FMT_MAKE_VALUE(Type, field, TYPE) \
FMT_MAKE_VALUE_(Type, field, TYPE, value)
FMT_MAKE_VALUE(bool, int_value, BOOL)
FMT_MAKE_VALUE(short, int_value, INT)
FMT_MAKE_VALUE(unsigned short, uint_value, UINT)
FMT_MAKE_VALUE(int, int_value, INT)
......@@ -907,7 +1061,9 @@ class MakeValue : public Arg {
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); } \
......@@ -919,6 +1075,7 @@ class MakeValue : public Arg {
FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING)
FMT_MAKE_STR_VALUE(const std::string &, STRING)
FMT_MAKE_STR_VALUE(StringRef, STRING)
FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str())
#define FMT_MAKE_WSTR_VALUE(Type, TYPE) \
MakeValue(typename WCharHelper<Type, Char>::Supported value) { \
......@@ -951,6 +1108,29 @@ class MakeValue : public Arg {
static uint64_t type(const T &) {
return IsConvertibleToInt<T>::value ? Arg::INT : Arg::CUSTOM;
}
// Additional template param `Char_` is needed here because make_type always
// uses MakeValue<char>.
template <typename Char_>
MakeValue(const NamedArg<Char_> &value) {
pointer = &value;
}
template <typename Char_>
static uint64_t type(const NamedArg<Char_> &) {
return Arg::NAMED_ARG;
}
};
template <typename Char>
struct NamedArg : Arg {
BasicStringRef<Char> name;
template <typename T>
NamedArg(BasicStringRef<Char> name, const T &value)
: name(name), Arg(MakeValue<Char>(value)) {
type = static_cast<internal::Arg::Type>(MakeValue<Char>::type(value));
}
};
#define FMT_DISPATCH(call) static_cast<Impl*>(this)->call
......@@ -977,7 +1157,7 @@ class MakeValue : public Arg {
// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
template <typename Impl, typename Result>
class ArgVisitor {
public:
public:
void report_unhandled_arg() {}
Result visit_unhandled_arg() {
......@@ -997,6 +1177,9 @@ class ArgVisitor {
Result visit_ulong_long(ULongLong value) {
return FMT_DISPATCH(visit_any_int(value));
}
Result visit_bool(bool value) {
return FMT_DISPATCH(visit_any_int(value));
}
Result visit_char(int value) {
return FMT_DISPATCH(visit_any_int(value));
}
......@@ -1032,7 +1215,7 @@ class ArgVisitor {
Result visit(const Arg &arg) {
switch (arg.type) {
default:
assert(false);
FMT_ASSERT(false, "invalid argument type");
return Result();
case Arg::INT:
return FMT_DISPATCH(visit_int(arg.int_value));
......@@ -1042,12 +1225,14 @@ class ArgVisitor {
return FMT_DISPATCH(visit_long_long(arg.long_long_value));
case Arg::ULONG_LONG:
return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value));
case Arg::BOOL:
return FMT_DISPATCH(visit_bool(arg.int_value != 0));
case Arg::CHAR:
return FMT_DISPATCH(visit_char(arg.int_value));
case Arg::DOUBLE:
return FMT_DISPATCH(visit_double(arg.double_value));
case Arg::LONG_DOUBLE:
return FMT_DISPATCH(visit_long_double(arg.long_double_value));
case Arg::CHAR:
return FMT_DISPATCH(visit_char(arg.int_value));
case Arg::CSTRING: {
Arg::StringValue<char> str = arg.string;
str.size = 0;
......@@ -1066,17 +1251,23 @@ class ArgVisitor {
};
class RuntimeError : public std::runtime_error {
protected:
protected:
RuntimeError() : std::runtime_error("") {}
};
template <typename Impl, typename Char>
class BasicArgFormatter;
template <typename Char>
class PrintfArgFormatter;
template <typename Char>
class ArgFormatter;
class ArgMap;
} // namespace internal
/** An argument list. */
class ArgList {
private:
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_;
......@@ -1097,13 +1288,15 @@ class ArgList {
(types_ & (mask << shift)) >> shift);
}
public:
template <typename Char>
friend class internal::ArgMap;
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)
......@@ -1140,21 +1333,36 @@ struct FormatSpec;
namespace internal {
template <std::size_t NUM_ARGS>
struct SelectValueType {
typedef typename Conditional<
(NUM_ARGS < ArgList::MAX_PACKED_ARGS), Value, Arg>::type Type;
template <typename Char>
class ArgMap {
private:
typedef std::map<fmt::BasicStringRef<Char>, internal::Arg> MapType;
typedef typename MapType::value_type Pair;
MapType map_;
public:
void init(const ArgList &args);
const internal::Arg* find(const fmt::BasicStringRef<Char> &name) const {
typename MapType::const_iterator it = map_.find(name);
return it != map_.end() ? &it->second : 0;
}
};
class FormatterBase {
private:
private:
ArgList args_;
int next_arg_index_;
// Returns the argument with specified index.
Arg do_get_arg(unsigned arg_index, const char *&error);
protected:
protected:
const ArgList &args() const {
return args_;
}
void set_args(const ArgList &args) {
args_ = args;
next_arg_index_ = 0;
......@@ -1167,6 +1375,8 @@ class FormatterBase {
// specified index.
Arg get_arg(unsigned arg_index, const char *&error);
bool check_no_auto_index(const char *&error);
template <typename Char>
void write(BasicWriter<Char> &w, const Char *start, const Char *end) {
if (start != end)
......@@ -1177,7 +1387,7 @@ class FormatterBase {
// A printf formatter.
template <typename Char>
class PrintfFormatter : private FormatterBase {
private:
private:
void parse_flags(FormatSpec &spec, const Char *&s);
// Returns the argument with specified index or, if arg_index is equal
......@@ -1188,30 +1398,42 @@ class PrintfFormatter : private FormatterBase {
// 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);
BasicCStringRef<Char> format_str, const ArgList &args);
};
} // namespace internal
// A formatter.
template <typename Char>
class BasicFormatter : private internal::FormatterBase {
private:
private:
BasicWriter<Char> &writer_;
const Char *start_;
internal::ArgMap<Char> map_;
FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter);
using FormatterBase::get_arg;
// Checks if manual indexing is used and returns the argument with
// specified name.
internal::Arg get_arg(BasicStringRef<Char> arg_name, const char *&error);
// Parses argument index and returns corresponding argument.
internal::Arg parse_arg_index(const Char *&s);
public:
// Parses argument name and returns corresponding argument.
internal::Arg parse_arg_name(const Char *&s);
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);
void format(BasicCStringRef<Char> format_str, const ArgList &args);
const Char *format(const Char *&format_str, const internal::Arg &arg);
};
......@@ -1232,12 +1454,24 @@ 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 ' '; }
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.
......@@ -1249,8 +1483,12 @@ 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.
......@@ -1260,9 +1498,13 @@ struct AlignSpec : WidthSpec {
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.
......@@ -1270,8 +1512,12 @@ template <char TYPE>
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.
......@@ -1284,73 +1530,86 @@ 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:
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>
template <typename Char>
class StrFormatSpec : public AlignSpec {
private:
const T *str_;
private:
const Char *str_;
public:
StrFormatSpec(const T *str, unsigned width, wchar_t fill)
: AlignSpec(width, fill), str_(str) {}
public:
template <typename FillChar>
StrFormatSpec(const Char *str, unsigned width, FillChar fill)
: AlignSpec(width, fill), str_(str) {
internal::CharTraits<Char>::convert(FillChar());
}
const T *str() const { return str_; }
const Char *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 = ' ');
......@@ -1358,26 +1617,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 */ \
......@@ -1389,20 +1648,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)
......@@ -1412,17 +1671,17 @@ 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 = ' ') {
......@@ -1454,16 +1713,73 @@ inline StrFormatSpec<wchar_t> pad(
# define FMT_GEN15(f) FMT_GEN14(f), f(14)
namespace internal {
inline uint64_t make_type() { return 0; }
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);
}
template <unsigned N>
struct ArgArray {
// 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.
enum { SIZE = N + (N == 0 || N >= ArgList::MAX_PACKED_ARGS ? 1 : 0) };
typedef typename Conditional<
(N < ArgList::MAX_PACKED_ARGS), Value, Arg>::type Type[SIZE];
};
#if FMT_USE_VARIADIC_TEMPLATES
template <typename Arg, typename... Args>
inline uint64_t make_type(const Arg &first, const Args & ... tail) {
return make_type(first) | (make_type(tail...) << 4);
}
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) {
if (check(sizeof...(Args) > ArgList::MAX_PACKED_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.
}
template <typename Char, typename Value>
inline void store_args(Value *) {}
template <typename Char, typename Arg, typename T, typename... Args>
inline void store_args(Arg *args, const T &arg, const Args & ... tail) {
// Assign only the Value subobject of Arg and don't overwrite type (if any)
// that is assigned by set_types.
Value &value = *args;
value = MakeValue<Char>(arg);
store_args<Char>(args + 1, tail...);
}
template <typename Char, typename... Args>
ArgList make_arg_list(typename ArgArray<sizeof...(Args)>::Type array,
const Args & ... args) {
if (check(sizeof...(Args) >= ArgList::MAX_PACKED_ARGS))
set_types(array, args...);
store_args<Char>(array, args...);
return ArgList(make_type(args...), array);
}
#else
struct ArgType {
......@@ -1497,24 +1813,16 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) {
# define FMT_VARIADIC_VOID(func, arg_type) \
template <typename... 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(arg0, ArgList(internal::make_type(args...), array)); \
typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
func(arg0, fmt::internal::make_arg_list<Char>(array, args...)); \
}
// 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) { \
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(internal::make_type(args...), array)); \
typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
func(arg0, arg1, fmt::internal::make_arg_list<Char>(array, args...)); \
}
#else
......@@ -1527,9 +1835,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 values[] = {FMT_GEN(n, FMT_MAKE_REF)}; \
const fmt::internal::ArgArray<n>::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \
func(arg1, fmt::ArgList( \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), values)); \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \
}
// Emulates a variadic function returning void on a pre-C++11 compiler.
......@@ -1544,9 +1852,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 values[] = {FMT_GEN(n, FMT_MAKE_REF)}; \
const fmt::internal::ArgArray<n>::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \
func(arg0, arg1, fmt::ArgList( \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), values)); \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \
}
// Emulates a variadic constructor on a pre-C++11 compiler.
......@@ -1586,21 +1894,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:
void init(int err_code, StringRef format_str, ArgList args);
private:
void init(int err_code, CStringRef 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
......@@ -1626,35 +1934,37 @@ class SystemError : public internal::RuntimeError {
throw fmt::SystemError(errno, "cannot open file '{}'", filename);
\endrst
*/
SystemError(int error_code, StringRef message) {
SystemError(int error_code, CStringRef message) {
init(error_code, message, ArgList());
}
FMT_VARIADIC_CTOR(SystemError, init, int, StringRef)
FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef)
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:
private:
// Output buffer.
Buffer<Char> &buffer_;
......@@ -1664,9 +1974,13 @@ class BasicWriter {
#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
......@@ -1729,31 +2043,39 @@ class BasicWriter {
template<typename T>
void append_float_length(Char *&, T) {}
friend class internal::ArgFormatter<Char>;
friend class internal::PrintfFormatter<Char>;
template <typename Impl, typename Char_>
friend class internal::BasicArgFormatter;
protected:
friend class internal::PrintfArgFormatter<Char>;
protected:
/**
Constructs a ``BasicWriter`` object.
*/
explicit BasicWriter(Buffer<Char> &b) : buffer_(b) {}
public:
public:
/**
\rst
Destroys a ``BasicWriter`` object.
\endrst
*/
virtual ~BasicWriter() {}
/**
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
......@@ -1767,7 +2089,9 @@ class BasicWriter {
}
/**
\rst
Returns the content of the output buffer as an `std::string`.
\endrst
*/
std::basic_string<Char> str() const {
return std::basic_string<Char>(&buffer_[0], buffer_.size());
......@@ -1798,10 +2122,10 @@ class BasicWriter {
See also :ref:`syntax`.
\endrst
*/
void write(BasicStringRef<Char> format, ArgList args) {
void write(BasicCStringRef<Char> format, ArgList args) {
BasicFormatter<Char>(*this).format(format, args);
}
FMT_VARIADIC_VOID(write, BasicStringRef<Char>)
FMT_VARIADIC_VOID(write, BasicCStringRef<Char>)
BasicWriter &operator<<(int value) {
return *this << IntFormatSpec<int>(value);
......@@ -1820,7 +2144,9 @@ class BasicWriter {
}
/**
\rst
Formats *value* and writes it to the stream.
\endrst
*/
BasicWriter &operator<<(ULongLong value) {
return *this << IntFormatSpec<ULongLong>(value);
......@@ -1832,8 +2158,10 @@ class BasicWriter {
}
/**
\rst
Formats *value* using the general format for floating-point numbers
(``'g'``) and writes it to the stream.
\endrst
*/
BasicWriter &operator<<(long double value) {
write_double(value, FormatSpec());
......@@ -1855,10 +2183,19 @@ class BasicWriter {
}
/**
\rst
Writes *value* to the stream.
\endrst
*/
BasicWriter &operator<<(fmt::BasicStringRef<Char> value) {
const Char *str = value.c_str();
const Char *str = value.data();
buffer_.append(str, str + value.size());
return *this;
}
BasicWriter &operator<<(
typename internal::WCharHelper<StringRef, Char>::Supported value) {
const char *str = value.data();
buffer_.append(str, str + value.size());
return *this;
}
......@@ -1873,12 +2210,11 @@ class BasicWriter {
template <typename StrChar>
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);
return *this;
}
void clear() FMT_NOEXCEPT { buffer_.clear(); }
void clear() FMT_NOEXCEPT{ buffer_.clear(); }
};
template <typename Char>
......@@ -1888,16 +2224,19 @@ typename BasicWriter<Char>::CharPtr BasicWriter<Char>::write_str(
CharPtr out = CharPtr();
if (spec.width() > size) {
out = grow_buffer(spec.width());
Char fill = static_cast<Char>(spec.fill());
Char fill = internal::CharTraits<Char>::cast(spec.fill());
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);
......@@ -1906,12 +2245,12 @@ 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 padding = total_size - content_size;
std::size_t left_padding = padding / 2;
Char fill_char = static_cast<Char>(fill);
Char fill_char = internal::CharTraits<Char>::cast(fill);
std::fill_n(buffer, left_padding, fill_char);
buffer += left_padding;
CharPtr content = buffer;
......@@ -1922,12 +2261,12 @@ typename BasicWriter<Char>::CharPtr
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) {
unsigned width = spec.width();
Alignment align = spec.align();
Char fill = static_cast<Char>(spec.fill());
Char fill = internal::CharTraits<Char>::cast(spec.fill());
if (spec.precision() > static_cast<int>(num_digits)) {
// Octal prefix '0' is counted as a digit, so ignore it if precision
// is specified.
......@@ -1963,17 +2302,20 @@ typename BasicWriter<Char>::CharPtr
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 {
}
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);
......@@ -1993,19 +2335,22 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
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': {
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)) {
prefix[prefix_size++] = '0';
......@@ -2025,7 +2370,8 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
} while ((n >>= 4) != 0);
break;
}
case 'b': case 'B': {
case 'b':
case 'B': {
UnsignedType n = abs_value;
if (spec.flag(HASH_FLAG)) {
prefix[prefix_size++] = '0';
......@@ -2075,7 +2421,10 @@ void BasicWriter<Char>::write_double(
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
......@@ -2083,7 +2432,9 @@ 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:
......@@ -2097,7 +2448,8 @@ void BasicWriter<Char>::write_double(
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) ? '+' : ' ';
}
......@@ -2141,7 +2493,7 @@ 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++ = '%';
......@@ -2150,7 +2502,8 @@ void BasicWriter<Char>::write_double(
*format_ptr++ = '#';
if (spec.align() == ALIGN_CENTER) {
width_for_sprintf = 0;
} else {
}
else {
if (spec.align() == ALIGN_LEFT)
*format_ptr++ = '-';
if (width != 0)
......@@ -2166,7 +2519,7 @@ void BasicWriter<Char>::write_double(
*format_ptr = '\0';
// Format using snprintf.
Char fill = static_cast<Char>(spec.fill());
Char fill = internal::CharTraits<Char>::cast(spec.fill());
for (;;) {
std::size_t buffer_size = buffer_.capacity() - offset;
#if _MSC_VER
......@@ -2187,7 +2540,8 @@ void BasicWriter<Char>::write_double(
*start != ' ') {
*(start - 1) = sign;
sign = 0;
} else {
}
else {
*(start - 1) = fill;
}
++n;
......@@ -2216,45 +2570,45 @@ void BasicWriter<Char>::write_double(
}
/**
\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.
\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 | BasicMemoryWriter<char, std::allocator<char>> |
+---------------+-----------------------------------------------------+
| WMemoryWriter | BasicMemoryWriter<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:
private:
internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE, Allocator> buffer_;
public:
public:
explicit BasicMemoryWriter(const Allocator& alloc = Allocator())
: BasicWriter<Char>(buffer_), buffer_(alloc) {}
......@@ -2285,31 +2639,31 @@ 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
*/
\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:
private:
internal::FixedBuffer<Char> buffer_;
public:
public:
/**
\rst
Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the
......@@ -2319,15 +2673,14 @@ class BasicArrayWriter : public BasicWriter<Char> {
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])
explicit BasicArrayWriter(Char(&array)[SIZE])
: BasicWriter<Char>(buffer_), buffer_(array, SIZE) {}
};
......@@ -2350,14 +2703,14 @@ void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value) {
// Can be used to report errors from destructors.
void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT;
#ifdef _WIN32
#if FMT_USE_WINDOWS_H
/** A Windows error. */
class WindowsError : public SystemError {
private:
void init(int error_code, StringRef format_str, ArgList args);
private:
void init(int error_code, CStringRef format_str, ArgList args);
public:
public:
/**
\rst
Constructs a :class:`fmt::WindowsError` object with the description
......@@ -2386,10 +2739,10 @@ class WindowsError : public SystemError {
}
\endrst
*/
WindowsError(int error_code, StringRef message) {
WindowsError(int error_code, CStringRef message) {
init(error_code, message, ArgList());
}
FMT_VARIADIC_CTOR(WindowsError, init, int, StringRef)
FMT_VARIADIC_CTOR(WindowsError, init, int, CStringRef)
};
// Reports a Windows error without throwing an exception.
......@@ -2401,119 +2754,119 @@ 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;
*/
void print_colored(Color c, StringRef format, ArgList args);
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, CStringRef 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(CStringRef 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(WCStringRef 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
*/
void print(std::FILE *f, StringRef format_str, ArgList args);
print(stderr, "Don't {}!", "panic");
\endrst
*/
void print(std::FILE *f, CStringRef 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
*/
void print(StringRef format_str, ArgList args);
print("Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
void print(CStringRef 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
*/
void print(std::ostream &os, StringRef format_str, ArgList args);
print(cerr, "Don't {}!", "panic");
\endrst
*/
void print(std::ostream &os, CStringRef format_str, ArgList args);
template <typename Char>
void printf(BasicWriter<Char> &w, BasicStringRef<Char> format, ArgList args) {
void printf(BasicWriter<Char> &w, BasicCStringRef<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(CStringRef 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
*/
int fprintf(std::FILE *f, StringRef format, ArgList args);
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
int fprintf(std::FILE *f, CStringRef 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(CStringRef format, ArgList args) {
return fprintf(stdout, format, args);
}
/**
Fast integer formatter.
*/
Fast integer formatter.
*/
class FormatInt {
private:
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_;
......@@ -2549,10 +2902,16 @@ class FormatInt {
*--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)) {}
......@@ -2560,13 +2919,17 @@ class FormatInt {
/**
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
......@@ -2578,9 +2941,13 @@ class FormatInt {
}
/**
Returns the content of the output buffer as an `std::string`.
\rst
Returns the content of the output buffer as an ``std::string``.
\endrst
*/
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
......@@ -2607,6 +2974,33 @@ inline void format_decimal(char *&buffer, T value) {
internal::format_decimal(buffer, abs_value, num_digits);
buffer += num_digits;
}
/**
\rst
Returns a named argument for formatting functions.
**Example**::
print("Elapsed time: {s:.2f} seconds", arg("s", 1.23));
\endrst
*/
template <typename T>
inline internal::NamedArg<char> arg(StringRef name, const T &arg) {
return internal::NamedArg<char>(name, arg);
}
template <typename T>
inline internal::NamedArg<wchar_t> arg(WStringRef name, const T &arg) {
return internal::NamedArg<wchar_t>(name, arg);
}
// The following two functions are deleted intentionally to disable
// nested named arguments as in ``format("{}", arg("a", arg("b", 42)))``.
template <typename Char>
void arg(StringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED;
template <typename Char>
void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED;
}
#if FMT_GCC_VERSION
......@@ -2637,52 +3031,13 @@ 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) { \
namespace internal = fmt::internal; \
typedef typename internal::SelectValueType<sizeof...(Args)>::Type Value; \
Value array[internal::ArgArraySize<sizeof...(Args)>::VALUE] = { \
internal::MakeValue<Char>(args)... \
}; \
if (internal::check((sizeof...(Args) > fmt::ArgList::MAX_PACKED_ARGS))) \
set_types(array, args...); \
typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \
call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \
fmt::ArgList(internal::make_type(args...), array)); \
fmt::internal::make_arg_list<Char>(array, args...)); \
}
#else
// Defines a wrapper for a function taking __VA_ARGS__ arguments
......@@ -2691,9 +3046,9 @@ struct ArgArraySize {
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 values[] = {FMT_GEN(n, FMT_MAKE_REF_##Char)}; \
fmt::internal::ArgArray<n>::Type arr = {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)), values)); \
fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr)); \
}
# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \
......@@ -2718,48 +3073,70 @@ struct ArgArraySize {
#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__)
#define FMT_CAPTURE_ARG_(id, index) ::fmt::arg(#id, id)
#define FMT_CAPTURE_ARG_W_(id, index) ::fmt::arg(L###id, id)
/**
\rst
Convenient macro to capture the arguments' names and values into several
``fmt::arg(name, value)``.
**Example**::
int x = 1, y = 2;
print("point: ({x}, {y})", FMT_CAPTURE(x, y));
// same as:
// print("point: ({x}, {y})", arg("x", x), arg("y", y));
\endrst
*/
#define FMT_CAPTURE(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_, __VA_ARGS__)
#define FMT_CAPTURE_W(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_W_, __VA_ARGS__)
namespace fmt {
FMT_VARIADIC(std::string, format, StringRef)
FMT_VARIADIC_W(std::wstring, format, WStringRef)
FMT_VARIADIC(void, print, StringRef)
FMT_VARIADIC(void, print, std::FILE *, StringRef)
FMT_VARIADIC(void, print, std::ostream &, StringRef)
FMT_VARIADIC(void, print_colored, Color, StringRef)
FMT_VARIADIC(std::string, sprintf, StringRef)
FMT_VARIADIC(int, printf, StringRef)
FMT_VARIADIC(int, fprintf, std::FILE *, StringRef)
FMT_VARIADIC(std::string, format, CStringRef)
FMT_VARIADIC_W(std::wstring, format, WCStringRef)
FMT_VARIADIC(void, print, CStringRef)
FMT_VARIADIC(void, print, std::FILE *, CStringRef)
FMT_VARIADIC(void, print, std::ostream &, CStringRef)
FMT_VARIADIC(void, print_colored, Color, CStringRef)
FMT_VARIADIC(std::string, sprintf, CStringRef)
FMT_VARIADIC(int, printf, CStringRef)
FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
}
// Restore warnings.
......
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