String: Add str_if_stable() as a const alternative to str()

The `str()` method must be non-const because it may need to internally
mutate the representation of the string in order to have an owned
`std::string` instance holding the exact string (not a superstring).
This is inconvenient in contexts where we can ensure that no mutation
is needed to get a `std::string const&`.

Add a `str_if_stable() const` method that returns `std::string const*`
so we can return `nullptr` if if mutation would be necessary to get a
`std::string const&`.  Add supporting `is_stable() const` and
`stabilize()` methods to check and enforce stable availability of
`std::string const&`.  These can be used to create `String const`
instances from which we can still get a `std::string const&` via
`*str_if_stable()` by maintaining the stability invariant at runtime.
This commit is contained in:
Brad King
2018-11-08 08:12:02 -05:00
parent a0841b59bd
commit 2d68b2c593
3 changed files with 97 additions and 3 deletions
+24 -3
View File
@@ -22,20 +22,41 @@ void String::internally_mutate_to_stable_string()
*this = String(data(), size());
}
std::string const& String::str()
bool String::is_stable() const
{
return str_if_stable() != nullptr;
}
void String::stabilize()
{
if (is_stable()) {
return;
}
this->internally_mutate_to_stable_string();
}
std::string const* String::str_if_stable() const
{
if (!data()) {
// We view no string.
// This is stable for the lifetime of our current value.
return empty_string_;
return &empty_string_;
}
if (string_ && data() == string_->data() && size() == string_->size()) {
// We view an entire string.
// This is stable for the lifetime of our current value.
return *string_;
return string_.get();
}
return nullptr;
}
std::string const& String::str()
{
if (std::string const* s = str_if_stable()) {
return *s;
}
// Mutate to hold a std::string that is stable for the lifetime
// of our current value.
this->internally_mutate_to_stable_string();