diff --git a/format.cc b/format.cc index 2abbab8c..ddfa4858 100644 --- a/format.cc +++ b/format.cc @@ -527,7 +527,7 @@ class PrintfArgFormatter : } // 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)); @@ -927,7 +927,7 @@ unsigned fmt::internal::PrintfFormatter::parse_header( template void fmt::internal::PrintfFormatter::format( - BasicWriter &writer, BasicStringRef format_str, + BasicWriter &writer, BasicCStringRef format_str, const ArgList &args) { const Char *start = format_str.c_str(); set_args(args); @@ -1198,7 +1198,7 @@ const Char *fmt::BasicFormatter::format( template void fmt::BasicFormatter::format( - BasicStringRef format_str, const ArgList &args) { + BasicCStringRef format_str, const ArgList &args) { const Char *s = start_ = format_str.c_str(); set_args(args); while (*s) { @@ -1230,23 +1230,23 @@ FMT_FUNC void fmt::report_windows_error( } #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(c); std::fputs(escape, stdout); @@ -1254,7 +1254,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(); @@ -1273,10 +1273,10 @@ template const char *fmt::BasicFormatter::format( const char *&format_str, const fmt::internal::Arg &arg); template void fmt::BasicFormatter::format( - BasicStringRef format, const ArgList &args); + CStringRef format, const ArgList &args); template void fmt::internal::PrintfFormatter::format( - BasicWriter &writer, BasicStringRef format, const ArgList &args); + BasicWriter &writer, CStringRef format, const ArgList &args); template int fmt::internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, @@ -1294,10 +1294,10 @@ template const wchar_t *fmt::BasicFormatter::format( const wchar_t *&format_str, const fmt::internal::Arg &arg); template void fmt::BasicFormatter::format( - BasicStringRef format, const ArgList &args); + BasicCStringRef format, const ArgList &args); template void fmt::internal::PrintfFormatter::format( - BasicWriter &writer, BasicStringRef format, + BasicWriter &writer, WCStringRef format, const ArgList &args); template int fmt::internal::CharTraits::format_float( diff --git a/format.h b/format.h index b4aee4c6..2156b3d3 100644 --- a/format.h +++ b/format.h @@ -206,8 +206,7 @@ void format(BasicFormatter &f, const Char *&format_str, const T &value); /** \rst - A string reference. It can be constructed from a C string or - ``std::string``. + 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: @@ -236,9 +235,7 @@ class BasicStringRef { std::size_t size_; public: - /** - Constructs a string reference object from a C string and a size. - */ + /** Constructs a string reference object from a C string and a size. */ BasicStringRef(const Char *s, std::size_t size) : data_(s), size_(size) {} /** @@ -264,17 +261,13 @@ class BasicStringRef { \endrst */ std::basic_string to_string() const { - return std::basic_string(data_, size()); + return std::basic_string(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. - */ + /** Returns the string size. */ std::size_t size() const { return size_; } friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { @@ -284,19 +277,69 @@ class BasicStringRef { 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_); + return std::lexicographical_compare( + lhs.data_, lhs.data_ + lhs.size_, rhs.data_, rhs.data_ + rhs.size_); } }; typedef BasicStringRef StringRef; typedef BasicStringRef 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 | + +-------------+--------------------------+ + | WCStringRef | BasicCStringRef | + +-------------+--------------------------+ + + This class is most useful as a parameter type to allow passing + different types of strings to a function, for example:: + + template + std::string format(CStringRef format_str, const Args & ... args); + + format("{}", 42); + format(std::string("{}"), 42); + \endrst + */ +template +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 &s) : data_(s.c_str()) {} + + /** Returns the pointer to a C string. */ + const Char *c_str() const { return data_; } +}; + +typedef BasicCStringRef CStringRef; +typedef BasicCStringRef WCStringRef; + /** A formatting error such as invalid format string. */ class FormatError : public std::runtime_error { public: - explicit FormatError(StringRef message) + explicit FormatError(CStringRef message) : std::runtime_error(message.c_str()) {} }; @@ -874,12 +917,12 @@ class MakeValue : public Arg { MakeValue(typename WCharHelper::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(); } @@ -895,10 +938,13 @@ class MakeValue : public Arg { 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; } +#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) @@ -952,6 +998,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::Supported value) { \ @@ -1270,7 +1317,7 @@ class PrintfFormatter : private FormatterBase { public: void format(BasicWriter &writer, - BasicStringRef format_str, const ArgList &args); + BasicCStringRef format_str, const ArgList &args); }; } // namespace internal @@ -1301,7 +1348,7 @@ class BasicFormatter : private internal::FormatterBase { BasicWriter &writer() { return writer_; } - void format(BasicStringRef format_str, const ArgList &args); + void format(BasicCStringRef format_str, const ArgList &args); const Char *format(const Char *&format_str, const internal::Arg &arg); }; @@ -1729,7 +1776,7 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { */ class SystemError : public internal::RuntimeError { private: - void init(int err_code, StringRef format_str, ArgList args); + void init(int err_code, CStringRef format_str, ArgList args); protected: int error_code_; @@ -1764,10 +1811,10 @@ 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_; } }; @@ -1942,10 +1989,10 @@ class BasicWriter { See also :ref:`syntax`. \endrst */ - void write(BasicStringRef format, ArgList args) { + void write(BasicCStringRef format, ArgList args) { BasicFormatter(*this).format(format, args); } - FMT_VARIADIC_VOID(write, BasicStringRef) + FMT_VARIADIC_VOID(write, BasicCStringRef) BasicWriter &operator<<(int value) { return *this << IntFormatSpec(value); @@ -2008,14 +2055,14 @@ class BasicWriter { \endrst */ BasicWriter &operator<<(fmt::BasicStringRef 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::Supported value) { - const char *str = value.c_str(); + const char *str = value.data(); buffer_.append(str, str + value.size()); return *this; } @@ -2561,7 +2608,7 @@ enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; Example: PrintColored(fmt::RED, "Elapsed time: {0:.2f} seconds") << 1.23; */ -void print_colored(Color c, StringRef format, ArgList args); +void print_colored(Color c, CStringRef format, ArgList args); /** \rst @@ -2572,13 +2619,13 @@ void print_colored(Color c, StringRef format, ArgList args); 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(); @@ -2593,7 +2640,7 @@ inline std::wstring format(WStringRef format_str, ArgList args) { print(stderr, "Don't {}!", "panic"); \endrst */ -void print(std::FILE *f, StringRef format_str, ArgList args); +void print(std::FILE *f, CStringRef format_str, ArgList args); /** \rst @@ -2604,7 +2651,7 @@ void print(std::FILE *f, StringRef format_str, ArgList args); print("Elapsed time: {0:.2f} seconds", 1.23); \endrst */ -void print(StringRef format_str, ArgList args); +void print(CStringRef format_str, ArgList args); /** \rst @@ -2615,10 +2662,10 @@ void print(StringRef format_str, ArgList args); print(cerr, "Don't {}!", "panic"); \endrst */ -void print(std::ostream &os, StringRef format_str, ArgList args); +void print(std::ostream &os, CStringRef format_str, ArgList args); template -void printf(BasicWriter &w, BasicStringRef format, ArgList args) { +void printf(BasicWriter &w, BasicCStringRef format, ArgList args) { internal::PrintfFormatter().format(w, format, args); } @@ -2631,7 +2678,7 @@ void printf(BasicWriter &w, BasicStringRef format, ArgList args) { 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(); @@ -2646,7 +2693,7 @@ inline std::string sprintf(StringRef format, ArgList args) { fmt::fprintf(stderr, "Don't %s!", "panic"); \endrst */ -int fprintf(std::FILE *f, StringRef format, ArgList args); +int fprintf(std::FILE *f, CStringRef format, ArgList args); /** \rst @@ -2657,7 +2704,7 @@ int fprintf(std::FILE *f, StringRef format, ArgList args); fmt::printf("Elapsed time: %.2f seconds", 1.23); \endrst */ -inline int printf(StringRef format, ArgList args) { +inline int printf(CStringRef format, ArgList args) { return fprintf(stdout, format, args); } @@ -2918,15 +2965,15 @@ void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; #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. diff --git a/posix.cc b/posix.cc index 4d0d22fa..d36871f4 100644 --- a/posix.cc +++ b/posix.cc @@ -83,7 +83,8 @@ fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT { fmt::report_system_error(errno, "cannot close file"); } -fmt::BufferedFile::BufferedFile(fmt::StringRef filename, fmt::StringRef mode) { +fmt::BufferedFile::BufferedFile( + fmt::CStringRef filename, fmt::CStringRef mode) { FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0); if (!file_) throw SystemError(errno, "cannot open file {}", filename); @@ -108,7 +109,7 @@ int fmt::BufferedFile::fileno() const { return fd; } -fmt::File::File(fmt::StringRef path, int oflag) { +fmt::File::File(fmt::CStringRef path, int oflag) { int mode = S_IRUSR | S_IWUSR; #if defined(_WIN32) && !defined(__MINGW32__) fd_ = -1; diff --git a/posix.h b/posix.h index 068f6638..722690a8 100644 --- a/posix.h +++ b/posix.h @@ -181,7 +181,7 @@ public: #endif // Opens a file. - BufferedFile(fmt::StringRef filename, fmt::StringRef mode); + BufferedFile(CStringRef filename, CStringRef mode); // Closes the file. void close(); @@ -193,10 +193,10 @@ public: // of MinGW that define fileno as a macro. int (fileno)() const; - void print(fmt::StringRef format_str, const ArgList &args) { + void print(CStringRef format_str, const ArgList &args) { fmt::print(file_, format_str, args); } - FMT_VARIADIC(void, print, fmt::StringRef) + FMT_VARIADIC(void, print, CStringRef) }; // A file. Closed file is represented by a File object with descriptor -1. @@ -224,7 +224,7 @@ class File { File() FMT_NOEXCEPT : fd_(-1) {} // Opens a file and constructs a File object representing this file. - File(fmt::StringRef path, int oflag); + File(CStringRef path, int oflag); #if !FMT_USE_RVALUE_REFERENCES // Emulate a move constructor and a move assignment operator if rvalue @@ -296,7 +296,7 @@ class File { void close(); // Returns the file size. - fmt::LongLong size() const; + LongLong size() const; // Attempts to read count bytes from the file into the specified buffer. std::size_t read(void *buffer, std::size_t count); diff --git a/test/format-test.cc b/test/format-test.cc index 8165b1d6..7af80251 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -66,6 +66,7 @@ using fmt::BasicWriter; using fmt::format; using fmt::FormatError; using fmt::StringRef; +using fmt::CStringRef; using fmt::MemoryWriter; using fmt::WMemoryWriter; using fmt::pad; @@ -136,6 +137,24 @@ struct WriteChecker { EXPECT_PRED_FORMAT1(WriteChecker(), value) } // namespace +TEST(StringRefTest, Ctor) { + EXPECT_STREQ("abc", StringRef("abc").data()); + EXPECT_EQ(3u, StringRef("abc").size()); + + EXPECT_STREQ("defg", StringRef(std::string("defg")).data()); + EXPECT_EQ(4u, StringRef(std::string("defg")).size()); +} + +TEST(StringRefTest, ConvertToString) { + std::string s = StringRef("abc").to_string(); + EXPECT_EQ("abc", s); +} + +TEST(CStringRefTest, Ctor) { + EXPECT_STREQ("abc", CStringRef("abc").c_str()); + EXPECT_STREQ("defg", CStringRef(std::string("defg")).c_str()); +} + class TestString { private: std::string value_; @@ -583,7 +602,7 @@ TEST(FormatterTest, ArgErrors) { template struct TestFormat { template - static std::string format(fmt::StringRef format_str, const Args & ... args) { + static std::string format(fmt::CStringRef format_str, const Args & ... args) { return TestFormat::format(format_str, N - 1, args...); } }; @@ -591,7 +610,7 @@ struct TestFormat { template <> struct TestFormat<0> { template - static std::string format(fmt::StringRef format_str, const Args & ... args) { + static std::string format(fmt::CStringRef format_str, const Args & ... args) { return fmt::format(format_str, args...); } }; @@ -1372,6 +1391,10 @@ TEST(FormatterTest, FormatStringRef) { EXPECT_EQ("test", format("{0}", StringRef("test"))); } +TEST(FormatterTest, FormatCStringRef) { + EXPECT_EQ("test", format("{0}", CStringRef("test"))); +} + TEST(FormatterTest, FormatUsingIOStreams) { EXPECT_EQ("a string", format("{0}", TestString("a string"))); std::string s = format("The date is {0}", Date(2012, 12, 9)); @@ -1440,19 +1463,6 @@ TEST(FormatterTest, FormatExamples) { }, error_code, "Cannot open file 'nonexistent'"); } -TEST(StringRefTest, Ctor) { - EXPECT_STREQ("abc", StringRef("abc").c_str()); - EXPECT_EQ(3u, StringRef("abc").size()); - - EXPECT_STREQ("defg", StringRef(std::string("defg")).c_str()); - EXPECT_EQ(4u, StringRef(std::string("defg")).size()); -} - -TEST(StringRefTest, ConvertToString) { - std::string s = StringRef("abc").to_string(); - EXPECT_EQ("abc", s); -} - TEST(FormatterTest, Examples) { EXPECT_EQ("First, thou shalt count to three", format("First, thou shalt count to {0}", "three")); diff --git a/test/posix-mock-test.cc b/test/posix-mock-test.cc index 0c513403..521eb035 100644 --- a/test/posix-mock-test.cc +++ b/test/posix-mock-test.cc @@ -207,7 +207,7 @@ int (test::fileno)(FILE *stream) { # define EXPECT_EQ_POSIX(expected, actual) #endif -void write_file(fmt::StringRef filename, fmt::StringRef content) { +void write_file(fmt::CStringRef filename, fmt::StringRef content) { fmt::BufferedFile f(filename, "w"); f.print("{}", content); } diff --git a/test/posix-test.cc b/test/posix-test.cc index 23bfb426..725c1507 100644 --- a/test/posix-test.cc +++ b/test/posix-test.cc @@ -64,7 +64,7 @@ File open_file() { // Attempts to write a string to a file. void write(File &f, fmt::StringRef s) { std::size_t num_chars_left = s.size(); - const char *ptr = s.c_str(); + const char *ptr = s.data(); do { std::streamsize count = f.write(ptr, num_chars_left); ptr += count;