mirror of
https://github.com/fmtlib/fmt.git
synced 2025-08-02 20:24:43 +02:00
Workaround a bug in Visual C++.
This commit is contained in:
148
format.h
148
format.h
@@ -37,6 +37,8 @@
|
|||||||
|
|
||||||
namespace format {
|
namespace format {
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
// A simple array for POD types with the first SIZE elements stored in
|
// A simple array for POD types with the first SIZE elements stored in
|
||||||
// the object itself. It supports a subset of std::vector's operations.
|
// the object itself. It supports a subset of std::vector's operations.
|
||||||
template <typename T, std::size_t SIZE>
|
template <typename T, std::size_t SIZE>
|
||||||
@@ -111,6 +113,9 @@ void Array<T, SIZE>::append(const T *begin, const T *end) {
|
|||||||
size_ += num_elements;
|
size_ += num_elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ArgInserter;
|
||||||
|
}
|
||||||
|
|
||||||
class FormatError : public std::runtime_error {
|
class FormatError : public std::runtime_error {
|
||||||
public:
|
public:
|
||||||
explicit FormatError(const std::string &message)
|
explicit FormatError(const std::string &message)
|
||||||
@@ -134,7 +139,7 @@ class FormatError : public std::runtime_error {
|
|||||||
class Formatter {
|
class Formatter {
|
||||||
private:
|
private:
|
||||||
enum { INLINE_BUFFER_SIZE = 500 };
|
enum { INLINE_BUFFER_SIZE = 500 };
|
||||||
Array<char, INLINE_BUFFER_SIZE> buffer_; // Output buffer.
|
internal::Array<char, INLINE_BUFFER_SIZE> buffer_; // Output buffer.
|
||||||
|
|
||||||
enum Type {
|
enum Type {
|
||||||
// Numeric types should go first.
|
// Numeric types should go first.
|
||||||
@@ -236,73 +241,11 @@ class Formatter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum { NUM_INLINE_ARGS = 10 };
|
enum { NUM_INLINE_ARGS = 10 };
|
||||||
Array<const Arg*, NUM_INLINE_ARGS> args_; // Format arguments.
|
internal::Array<const Arg*, NUM_INLINE_ARGS> args_; // Format arguments.
|
||||||
|
|
||||||
const char *format_; // Format string.
|
const char *format_; // Format string.
|
||||||
|
|
||||||
template <typename Action>
|
friend class internal::ArgInserter;
|
||||||
friend class ActiveFormatter;
|
|
||||||
|
|
||||||
// This is a transient object that normally exists only as a temporary
|
|
||||||
// returned by one of the formatting functions. It stores a reference
|
|
||||||
// to a formatter and provides operator<< that feeds arguments to the
|
|
||||||
// formatter.
|
|
||||||
class ArgInserter {
|
|
||||||
private:
|
|
||||||
mutable Formatter *formatter_;
|
|
||||||
|
|
||||||
friend class Formatter;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
explicit ArgInserter(Formatter *f = 0) : formatter_(f) {}
|
|
||||||
|
|
||||||
ArgInserter(ArgInserter& other)
|
|
||||||
: formatter_(other.formatter_) {
|
|
||||||
other.formatter_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ArgInserter& operator=(const ArgInserter& other) {
|
|
||||||
formatter_ = other.formatter_;
|
|
||||||
other.formatter_ = 0;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Formatter *Format() const {
|
|
||||||
Formatter *f = formatter_;
|
|
||||||
if (f) {
|
|
||||||
formatter_ = 0;
|
|
||||||
f->Format();
|
|
||||||
}
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
Formatter *formatter() const { return formatter_; }
|
|
||||||
|
|
||||||
void ResetFormatter() { formatter_ = 0; }
|
|
||||||
|
|
||||||
public:
|
|
||||||
~ArgInserter() {
|
|
||||||
if (formatter_)
|
|
||||||
formatter_->Format();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Feeds an argument to a formatter.
|
|
||||||
ArgInserter &operator<<(const Formatter::Arg &arg) {
|
|
||||||
arg.formatter = formatter_;
|
|
||||||
formatter_->Add(arg);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Performs formatting and returns a C string with the output.
|
|
||||||
friend const char *c_str(const ArgInserter &af) {
|
|
||||||
return af.Format()->c_str();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Performs formatting and returns a std::string with the output.
|
|
||||||
friend std::string str(const ArgInserter &af) {
|
|
||||||
return af.Format()->str();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void Add(const Arg &arg) {
|
void Add(const Arg &arg) {
|
||||||
args_.push_back(&arg);
|
args_.push_back(&arg);
|
||||||
@@ -342,7 +285,7 @@ class Formatter {
|
|||||||
// Formats a string appending the output to the internal buffer.
|
// Formats a string appending the output to the internal buffer.
|
||||||
// Arguments are accepted through the returned ArgInserter object
|
// Arguments are accepted through the returned ArgInserter object
|
||||||
// using inserter operator<<.
|
// using inserter operator<<.
|
||||||
ArgInserter operator()(const char *format);
|
internal::ArgInserter operator()(const char *format);
|
||||||
|
|
||||||
std::size_t size() const { return buffer_.size(); }
|
std::size_t size() const { return buffer_.size(); }
|
||||||
|
|
||||||
@@ -352,6 +295,71 @@ class Formatter {
|
|||||||
std::string str() const { return std::string(&buffer_[0], buffer_.size()); }
|
std::string str() const { return std::string(&buffer_[0], buffer_.size()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// This is a transient object that normally exists only as a temporary
|
||||||
|
// returned by one of the formatting functions. It stores a reference
|
||||||
|
// to a formatter and provides operator<< that feeds arguments to the
|
||||||
|
// formatter.
|
||||||
|
class ArgInserter {
|
||||||
|
private:
|
||||||
|
mutable Formatter *formatter_;
|
||||||
|
|
||||||
|
friend class format::Formatter;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit ArgInserter(Formatter *f = 0) : formatter_(f) {}
|
||||||
|
|
||||||
|
ArgInserter(ArgInserter& other)
|
||||||
|
: formatter_(other.formatter_) {
|
||||||
|
other.formatter_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgInserter& operator=(const ArgInserter& other) {
|
||||||
|
formatter_ = other.formatter_;
|
||||||
|
other.formatter_ = 0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Formatter *Format() const {
|
||||||
|
Formatter *f = formatter_;
|
||||||
|
if (f) {
|
||||||
|
formatter_ = 0;
|
||||||
|
f->Format();
|
||||||
|
}
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Formatter *formatter() const { return formatter_; }
|
||||||
|
const char *format() const { return formatter_->format_; }
|
||||||
|
|
||||||
|
void ResetFormatter() { formatter_ = 0; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
~ArgInserter() {
|
||||||
|
if (formatter_)
|
||||||
|
formatter_->Format();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feeds an argument to a formatter.
|
||||||
|
ArgInserter &operator<<(const Formatter::Arg &arg) {
|
||||||
|
arg.formatter = formatter_;
|
||||||
|
formatter_->Add(arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Performs formatting and returns a C string with the output.
|
||||||
|
friend const char *c_str(const ArgInserter &af) {
|
||||||
|
return af.Format()->c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Performs formatting and returns a std::string with the output.
|
||||||
|
friend std::string str(const ArgInserter &af) {
|
||||||
|
return af.Format()->str();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void Formatter::FormatCustomArg(const void *arg, int width) {
|
void Formatter::FormatCustomArg(const void *arg, int width) {
|
||||||
const T &value = *static_cast<const T*>(arg);
|
const T &value = *static_cast<const T*>(arg);
|
||||||
@@ -364,8 +372,8 @@ void Formatter::FormatCustomArg(const void *arg, int width) {
|
|||||||
std::fill_n(out + str.size(), width - str.size(), ' ');
|
std::fill_n(out + str.size(), width - str.size(), ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Formatter::ArgInserter Formatter::operator()(const char *format) {
|
inline internal::ArgInserter Formatter::operator()(const char *format) {
|
||||||
ArgInserter formatter(this);
|
internal::ArgInserter formatter(this);
|
||||||
format_ = format;
|
format_ = format;
|
||||||
args_.clear();
|
args_.clear();
|
||||||
return formatter;
|
return formatter;
|
||||||
@@ -375,7 +383,7 @@ inline Formatter::ArgInserter Formatter::operator()(const char *format) {
|
|||||||
// This is a transient object that normally exists only as a temporary
|
// This is a transient object that normally exists only as a temporary
|
||||||
// returned by one of the formatting functions.
|
// returned by one of the formatting functions.
|
||||||
template <typename Action>
|
template <typename Action>
|
||||||
class ActiveFormatter : public Formatter::ArgInserter {
|
class ActiveFormatter : public internal::ArgInserter {
|
||||||
private:
|
private:
|
||||||
Formatter formatter_;
|
Formatter formatter_;
|
||||||
Action action_;
|
Action action_;
|
||||||
@@ -400,8 +408,8 @@ class ActiveFormatter : public Formatter::ArgInserter {
|
|||||||
// are provided.
|
// are provided.
|
||||||
ActiveFormatter(ActiveFormatter &other)
|
ActiveFormatter(ActiveFormatter &other)
|
||||||
: ArgInserter(0), action_(other.action_) {
|
: ArgInserter(0), action_(other.action_) {
|
||||||
|
ArgInserter::operator=(formatter_(other.format()));
|
||||||
other.ResetFormatter();
|
other.ResetFormatter();
|
||||||
ArgInserter::operator=(formatter_(other.formatter_.format_));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~ActiveFormatter() {
|
~ActiveFormatter() {
|
||||||
|
@@ -35,6 +35,7 @@
|
|||||||
using std::size_t;
|
using std::size_t;
|
||||||
using std::sprintf;
|
using std::sprintf;
|
||||||
|
|
||||||
|
using fmt::internal::Array;
|
||||||
using fmt::Formatter;
|
using fmt::Formatter;
|
||||||
using fmt::Format;
|
using fmt::Format;
|
||||||
using fmt::FormatError;
|
using fmt::FormatError;
|
||||||
@@ -90,23 +91,23 @@ class TestString {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TEST(ArrayTest, Ctor) {
|
TEST(ArrayTest, Ctor) {
|
||||||
fmt::Array<char, 123> array;
|
Array<char, 123> array;
|
||||||
EXPECT_EQ(0u, array.size());
|
EXPECT_EQ(0u, array.size());
|
||||||
EXPECT_EQ(123u, array.capacity());
|
EXPECT_EQ(123u, array.capacity());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ArrayTest, Access) {
|
TEST(ArrayTest, Access) {
|
||||||
fmt::Array<char, 10> array;
|
Array<char, 10> array;
|
||||||
array[0] = 11;
|
array[0] = 11;
|
||||||
EXPECT_EQ(11, array[0]);
|
EXPECT_EQ(11, array[0]);
|
||||||
array[3] = 42;
|
array[3] = 42;
|
||||||
EXPECT_EQ(42, *(&array[0] + 3));
|
EXPECT_EQ(42, *(&array[0] + 3));
|
||||||
const fmt::Array<char, 10> &carray = array;
|
const Array<char, 10> &carray = array;
|
||||||
EXPECT_EQ(42, carray[3]);
|
EXPECT_EQ(42, carray[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ArrayTest, Resize) {
|
TEST(ArrayTest, Resize) {
|
||||||
fmt::Array<char, 123> array;
|
Array<char, 123> array;
|
||||||
array[10] = 42;
|
array[10] = 42;
|
||||||
EXPECT_EQ(42, array[10]);
|
EXPECT_EQ(42, array[10]);
|
||||||
array.resize(20);
|
array.resize(20);
|
||||||
@@ -120,7 +121,7 @@ TEST(ArrayTest, Resize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ArrayTest, Grow) {
|
TEST(ArrayTest, Grow) {
|
||||||
fmt::Array<int, 10> array;
|
Array<int, 10> array;
|
||||||
array.resize(10);
|
array.resize(10);
|
||||||
for (int i = 0; i < 10; ++i)
|
for (int i = 0; i < 10; ++i)
|
||||||
array[i] = i * i;
|
array[i] = i * i;
|
||||||
@@ -132,7 +133,7 @@ TEST(ArrayTest, Grow) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ArrayTest, Clear) {
|
TEST(ArrayTest, Clear) {
|
||||||
fmt::Array<char, 10> array;
|
Array<char, 10> array;
|
||||||
array.resize(20);
|
array.resize(20);
|
||||||
array.clear();
|
array.clear();
|
||||||
EXPECT_EQ(0u, array.size());
|
EXPECT_EQ(0u, array.size());
|
||||||
@@ -140,7 +141,7 @@ TEST(ArrayTest, Clear) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ArrayTest, PushBack) {
|
TEST(ArrayTest, PushBack) {
|
||||||
fmt::Array<int, 10> array;
|
Array<int, 10> array;
|
||||||
array.push_back(11);
|
array.push_back(11);
|
||||||
EXPECT_EQ(11, array[0]);
|
EXPECT_EQ(11, array[0]);
|
||||||
EXPECT_EQ(1u, array.size());
|
EXPECT_EQ(1u, array.size());
|
||||||
@@ -152,7 +153,7 @@ TEST(ArrayTest, PushBack) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ArrayTest, Append) {
|
TEST(ArrayTest, Append) {
|
||||||
fmt::Array<char, 10> array;
|
Array<char, 10> array;
|
||||||
const char *test = "test";
|
const char *test = "test";
|
||||||
array.append(test, test + 5);
|
array.append(test, test + 5);
|
||||||
EXPECT_STREQ("test", &array[0]);
|
EXPECT_STREQ("test", &array[0]);
|
||||||
|
Reference in New Issue
Block a user