diff --git a/format.h b/format.h index 24dddd69..6e8303d0 100644 --- a/format.h +++ b/format.h @@ -309,7 +309,32 @@ class Formatter { void Write(const std::string &s, unsigned width); }; -class StringRef; +// A reference to a string. It can be constructed from a C string, +// std::string or as a result of a formatting operation. It is most useful +// as a parameter type to allow passing different types of strings in a +// function, for example: +// void SetName(StringRef s) { +// std::string name = s; +// ... +// } +class StringRef { + private: + const char *data_; + mutable std::size_t size_; + + public: + StringRef(const char *s, std::size_t size = 0) : data_(s), size_(size) {} + StringRef(const std::string &s) : data_(s.c_str()), size_(s.size()) {} + + operator std::string() const { return std::string(data_, size()); } + + const char *c_str() const { return data_; } + + std::size_t size() const { + if (size_ == 0) size_ = std::strlen(data_); + return size_; + } +}; namespace internal { @@ -384,6 +409,11 @@ class ArgInserter { return Proxy(f); } + operator StringRef() { + const Formatter *f = Format(); + return StringRef(f->c_str(), f->size()); + } + // Performs formatting and returns a std::string with the output. friend std::string str(Proxy p) { return p.Format()->str(); @@ -402,39 +432,6 @@ const char *c_str(ArgInserter::Proxy p); using format::internal::str; using format::internal::c_str; -// A reference to a string. It can be constructed from a C string, -// std::string or as a result of a formatting operation. It is most useful -// as a parameter type to allow passing different types of strings in a -// function, for example: -// void SetName(StringRef s) { -// std::string name = s; -// ... -// } -class StringRef { - private: - const char *data_; - mutable std::size_t size_; - - public: - StringRef(const char *s) : data_(s), size_(0) {} - StringRef(const std::string &s) : data_(s.c_str()), size_(s.size()) {} - - StringRef(internal::ArgInserter::Proxy p) { - Formatter *f = p.Format(); - data_ = f->c_str(); - size_ = f->size(); - } - - operator std::string() const { return std::string(data_, size_); } - - const char *c_str() const { return data_; } - - std::size_t size() const { - if (size_ == 0) size_ = std::strlen(data_); - return size_; - } -}; - // ArgFormatter provides access to the format buffer within custom // Format functions. It is not desirable to pass Formatter to these // functions because Formatter::operator() is not reentrant and diff --git a/format_test.cc b/format_test.cc index 7c1020bb..b4f2f27c 100644 --- a/format_test.cc +++ b/format_test.cc @@ -735,15 +735,17 @@ TEST(FormatterTest, StrNamespace) { fmt::c_str(Format("")); } -TEST(FormatterTest, StringRef) { +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()); +} - EXPECT_STREQ("hijkl", StringRef(Format("hi{0}kl") << 'j').c_str()); - EXPECT_EQ(5u, StringRef(Format("hi{0}kl") << 'j').size()); +TEST(StringRefTest, ConvertToString) { + std::string s = StringRef("abc"); + EXPECT_EQ("abc", s); } struct CountCalls { @@ -791,6 +793,11 @@ TEST(TempFormatterTest, ArgLifetime) { } #endif +TEST(TempFormatterTest, ConvertToStringRef) { + EXPECT_STREQ("abc", StringRef(Format("a{0}c") << 'b').c_str()); + EXPECT_EQ(3u, StringRef(Format("a{0}c") << 'b').size()); +} + struct PrintError { void operator()(const fmt::Formatter &f) const { std::cerr << "Error: " << f.str() << std::endl;