Refactor StringRef.

This commit is contained in:
Victor Zverovich 2012-12-19 10:47:00 -08:00
parent a145b4c61c
commit 30ab349173
2 changed files with 41 additions and 37 deletions

View File

@ -309,7 +309,32 @@ class Formatter {
void Write(const std::string &s, unsigned width); 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 { namespace internal {
@ -384,6 +409,11 @@ class ArgInserter {
return Proxy(f); 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. // Performs formatting and returns a std::string with the output.
friend std::string str(Proxy p) { friend std::string str(Proxy p) {
return p.Format()->str(); return p.Format()->str();
@ -402,39 +432,6 @@ const char *c_str(ArgInserter::Proxy p);
using format::internal::str; using format::internal::str;
using format::internal::c_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 // ArgFormatter provides access to the format buffer within custom
// Format functions. It is not desirable to pass Formatter to these // Format functions. It is not desirable to pass Formatter to these
// functions because Formatter::operator() is not reentrant and // functions because Formatter::operator() is not reentrant and

View File

@ -735,15 +735,17 @@ TEST(FormatterTest, StrNamespace) {
fmt::c_str(Format("")); fmt::c_str(Format(""));
} }
TEST(FormatterTest, StringRef) { TEST(StringRefTest, Ctor) {
EXPECT_STREQ("abc", StringRef("abc").c_str()); EXPECT_STREQ("abc", StringRef("abc").c_str());
EXPECT_EQ(3u, StringRef("abc").size()); EXPECT_EQ(3u, StringRef("abc").size());
EXPECT_STREQ("defg", StringRef(std::string("defg")).c_str()); EXPECT_STREQ("defg", StringRef(std::string("defg")).c_str());
EXPECT_EQ(4u, StringRef(std::string("defg")).size()); EXPECT_EQ(4u, StringRef(std::string("defg")).size());
}
EXPECT_STREQ("hijkl", StringRef(Format("hi{0}kl") << 'j').c_str()); TEST(StringRefTest, ConvertToString) {
EXPECT_EQ(5u, StringRef(Format("hi{0}kl") << 'j').size()); std::string s = StringRef("abc");
EXPECT_EQ("abc", s);
} }
struct CountCalls { struct CountCalls {
@ -791,6 +793,11 @@ TEST(TempFormatterTest, ArgLifetime) {
} }
#endif #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 { struct PrintError {
void operator()(const fmt::Formatter &f) const { void operator()(const fmt::Formatter &f) const {
std::cerr << "Error: " << f.str() << std::endl; std::cerr << "Error: " << f.str() << std::endl;