ImmutableString: Ensure that c_str() returns non-nullptr if it is default constructed

This commit is contained in:
Tatsuhiro Tsujikawa 2016-01-17 18:00:36 +09:00
parent ba543e3895
commit 5131b95c2f
2 changed files with 27 additions and 20 deletions

View File

@ -215,10 +215,7 @@ inline std::unique_ptr<char[]> strcopy(const std::unique_ptr<char[]> &val,
// std::string. It has c_str() and size() functions to mimic
// std::string. It manages buffer by itself. Just like std::string,
// c_str() returns NULL-terminated string, but NULL character may
// appear before the final terminal NULL. The crucial difference
// between this and std::string is that when ImmutableString is
// default constructed, c_str() returns nullptr, whereas std::string
// will return non nullptr. Both size() returns 0.
// appear before the final terminal NULL.
class ImmutableString {
public:
using traits_type = std::char_traits<char>;
@ -231,24 +228,30 @@ public:
using const_pointer = const value_type *;
using const_iterator = const_pointer;
ImmutableString() : len(0) {}
ImmutableString() : len(0), base("") {}
ImmutableString(const char *s, size_t slen)
: len(slen), base(strcopy(s, len)) {}
ImmutableString(const char *s) : len(strlen(s)), base(strcopy(s, len)) {}
: len(slen), holder(strcopy(s, len)), base(holder.get()) {}
ImmutableString(const char *s)
: len(strlen(s)), holder(strcopy(s, len)), base(holder.get()) {}
ImmutableString(std::unique_ptr<char[]> s)
: len(strlen(s.get())), base(std::move(s)) {}
: len(strlen(s.get())), holder(std::move(s)), base(holder.get()) {}
ImmutableString(std::unique_ptr<char[]> s, size_t slen)
: len(slen), base(std::move(s)) {}
ImmutableString(const std::string &s) : len(s.size()), base(strcopy(s)) {}
: len(slen), holder(std::move(s)), base(holder.get()) {}
ImmutableString(const std::string &s)
: len(s.size()), holder(strcopy(s)), base(holder.get()) {}
template <typename InputIt>
ImmutableString(InputIt first, InputIt last)
: len(std::distance(first, last)), base(strcopy(first, last)) {}
: len(std::distance(first, last)), holder(strcopy(first, last)),
base(holder.get()) {}
ImmutableString(const ImmutableString &other)
: len(other.len), base(strcopy(other.base, other.len)) {}
: len(other.len), holder(strcopy(other.holder, other.len)),
base(holder.get()) {}
ImmutableString(ImmutableString &&other) noexcept
: len(other.len),
base(std::move(other.base)) {
holder(std::move(other.holder)),
base(holder.get()) {
other.len = 0;
other.base = "";
}
ImmutableString &operator=(const ImmutableString &other) {
@ -256,7 +259,8 @@ public:
return *this;
}
len = other.len;
base = strcopy(other.base, other.len);
holder = strcopy(other.holder, other.len);
base = holder.get();
return *this;
}
ImmutableString &operator=(ImmutableString &&other) noexcept {
@ -264,8 +268,10 @@ public:
return *this;
}
len = other.len;
base = std::move(other.base);
holder = std::move(other.holder);
base = holder.get();
other.len = 0;
other.base = "";
return *this;
}
@ -273,12 +279,13 @@ public:
return ImmutableString(s, N - 1);
}
const char *c_str() const { return base.get(); }
const char *c_str() const { return base; }
size_type size() const { return len; }
private:
size_type len;
std::unique_ptr<char[]> base;
std::unique_ptr<char[]> holder;
const char *base;
};
// StringRef is a reference to a string owned by something else. So

View File

@ -36,7 +36,7 @@ namespace nghttp2 {
void test_template_immutable_string(void) {
ImmutableString null;
CU_ASSERT(nullptr == null.c_str());
CU_ASSERT("" == null);
CU_ASSERT(0 == null.size());
ImmutableString from_cstr("alpha");
@ -71,7 +71,7 @@ void test_template_immutable_string(void) {
CU_ASSERT("charlie" == move);
CU_ASSERT(7 == move.size());
CU_ASSERT(nullptr == copy.c_str());
CU_ASSERT("" == copy);
CU_ASSERT(0 == copy.size());
// move assignment
@ -79,7 +79,7 @@ void test_template_immutable_string(void) {
CU_ASSERT("alpha" == move);
CU_ASSERT(5 == move.size());
CU_ASSERT(nullptr == from_cstr.c_str());
CU_ASSERT("" == from_cstr);
CU_ASSERT(0 == from_cstr.size());
// from string literal