mirror of
https://github.com/reactos/CMake.git
synced 2025-01-22 11:24:56 +00:00
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:
parent
a0841b59bd
commit
2d68b2c593
@ -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();
|
||||
|
@ -348,6 +348,20 @@ public:
|
||||
|
||||
char back() const noexcept { return view_.back(); }
|
||||
|
||||
/** Return true if this instance is stable and otherwise false.
|
||||
An instance is stable if it is in the 'null' state or if it is
|
||||
an 'owned' state not produced by substring operations, or
|
||||
after a call to 'stabilize()' or 'str()'. */
|
||||
bool is_stable() const;
|
||||
|
||||
/** If 'is_stable()' does not return true, mutate so it does. */
|
||||
void stabilize();
|
||||
|
||||
/** Get a pointer to a normal std::string if 'is_stable()' returns
|
||||
true and otherwise nullptr. The pointer is valid until this
|
||||
instance is mutated or destroyed. */
|
||||
std::string const* str_if_stable() const;
|
||||
|
||||
/** Get a refernce to a normal std::string. The reference
|
||||
is valid until this instance is mutated or destroyed. */
|
||||
std::string const& str();
|
||||
|
@ -30,8 +30,10 @@ static bool testConstructDefault()
|
||||
ASSERT_TRUE(str_const.data() == nullptr);
|
||||
ASSERT_TRUE(str_const.size() == 0);
|
||||
ASSERT_TRUE(str_const.empty());
|
||||
ASSERT_TRUE(str_const.is_stable());
|
||||
ASSERT_TRUE(str.c_str() == nullptr);
|
||||
ASSERT_TRUE(str.str().empty());
|
||||
ASSERT_TRUE(str.is_stable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -42,8 +44,10 @@ static bool testFromNullPtr(cm::String str)
|
||||
ASSERT_TRUE(str_const.data() == nullptr);
|
||||
ASSERT_TRUE(str_const.size() == 0);
|
||||
ASSERT_TRUE(str_const.empty());
|
||||
ASSERT_TRUE(str_const.is_stable());
|
||||
ASSERT_TRUE(str.c_str() == nullptr);
|
||||
ASSERT_TRUE(str.str().empty());
|
||||
ASSERT_TRUE(str.is_stable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -68,8 +72,10 @@ static bool testFromCStrNull(cm::String str)
|
||||
ASSERT_TRUE(str_const.data() == nullptr);
|
||||
ASSERT_TRUE(str_const.size() == 0);
|
||||
ASSERT_TRUE(str_const.empty());
|
||||
ASSERT_TRUE(str_const.is_stable());
|
||||
ASSERT_TRUE(str.c_str() == nullptr);
|
||||
ASSERT_TRUE(str.str().empty());
|
||||
ASSERT_TRUE(str.is_stable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -96,12 +102,16 @@ static bool testFromCharArray(cm::String str)
|
||||
cm::String const& str_const = str;
|
||||
ASSERT_TRUE(str_const.data() != charArray);
|
||||
ASSERT_TRUE(str_const.size() == sizeof(charArray) - 1);
|
||||
ASSERT_TRUE(str_const.is_stable());
|
||||
ASSERT_TRUE(str.c_str() != charArray);
|
||||
ASSERT_TRUE(str.is_stable());
|
||||
cm::String substr = str.substr(1);
|
||||
cm::String const& substr_const = substr;
|
||||
ASSERT_TRUE(substr_const.data() != &charArray[1]);
|
||||
ASSERT_TRUE(substr_const.size() == 2);
|
||||
ASSERT_TRUE(!substr_const.is_stable());
|
||||
ASSERT_TRUE(substr.c_str() != &charArray[1]);
|
||||
ASSERT_TRUE(!substr.is_stable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -126,6 +136,7 @@ static bool testFromCStr(cm::String const& str)
|
||||
ASSERT_TRUE(str.data() != cstr);
|
||||
ASSERT_TRUE(str.size() == 3);
|
||||
ASSERT_TRUE(std::strncmp(str.data(), cstr, 3) == 0);
|
||||
ASSERT_TRUE(str.is_stable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -156,6 +167,7 @@ static bool testFromStdString(cm::String const& str)
|
||||
#endif
|
||||
ASSERT_TRUE(str.size() == 3);
|
||||
ASSERT_TRUE(std::strncmp(str.data(), stdstr.data(), 3) == 0);
|
||||
ASSERT_TRUE(str.is_stable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -193,6 +205,7 @@ static bool testFromChar(cm::String const& str)
|
||||
{
|
||||
ASSERT_TRUE(str.size() == 1);
|
||||
ASSERT_TRUE(std::strncmp(str.data(), "a", 1) == 0);
|
||||
ASSERT_TRUE(str.is_stable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -216,6 +229,7 @@ static bool testConstructFromInitList()
|
||||
cm::String const str{ 'a', 'b', 'c' };
|
||||
ASSERT_TRUE(str.size() == 3);
|
||||
ASSERT_TRUE(std::strncmp(str.data(), "abc", 3) == 0);
|
||||
ASSERT_TRUE(str.is_stable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -226,6 +240,7 @@ static bool testAssignFromInitList()
|
||||
str = { 'a', 'b', 'c' };
|
||||
ASSERT_TRUE(str.size() == 3);
|
||||
ASSERT_TRUE(std::strncmp(str.data(), "abc", 3) == 0);
|
||||
ASSERT_TRUE(str.is_stable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -243,6 +258,7 @@ static bool testConstructFromInputIterator()
|
||||
ASSERT_TRUE(str.data() != cstr);
|
||||
ASSERT_TRUE(str.size() == 3);
|
||||
ASSERT_TRUE(std::strncmp(str.data(), cstr, 3) == 0);
|
||||
ASSERT_TRUE(str.is_stable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -252,6 +268,7 @@ static bool testConstructFromN()
|
||||
cm::String const str(3, 'a');
|
||||
ASSERT_TRUE(str.size() == 3);
|
||||
ASSERT_TRUE(std::strncmp(str.data(), "aaa", 3) == 0);
|
||||
ASSERT_TRUE(str.is_stable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -262,12 +279,16 @@ static bool testFromStaticStringView(cm::String str)
|
||||
cm::String const& str_const = str;
|
||||
ASSERT_TRUE(str_const.data() == staticStringView.data());
|
||||
ASSERT_TRUE(str_const.size() == staticStringView.size());
|
||||
ASSERT_TRUE(!str_const.is_stable());
|
||||
ASSERT_TRUE(str.c_str() == staticStringView);
|
||||
ASSERT_TRUE(!str.is_stable());
|
||||
cm::String substr = str.substr(1);
|
||||
cm::String const& substr_const = substr;
|
||||
ASSERT_TRUE(substr_const.data() == &staticStringView[1]);
|
||||
ASSERT_TRUE(substr_const.size() == 2);
|
||||
ASSERT_TRUE(!substr_const.is_stable());
|
||||
ASSERT_TRUE(substr.c_str() == &staticStringView[1]);
|
||||
ASSERT_TRUE(!substr.is_stable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -294,6 +315,8 @@ static bool testConstructCopy()
|
||||
ASSERT_TRUE(s1.size() == 3);
|
||||
ASSERT_TRUE(s2.size() == 3);
|
||||
ASSERT_TRUE(std::strncmp(s2.data(), "abc", 3) == 0);
|
||||
ASSERT_TRUE(s1.is_stable());
|
||||
ASSERT_TRUE(s2.is_stable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -306,6 +329,8 @@ static bool testConstructMove()
|
||||
ASSERT_TRUE(s1.size() == 0);
|
||||
ASSERT_TRUE(s2.size() == 3);
|
||||
ASSERT_TRUE(std::strncmp(s2.data(), "abc", 3) == 0);
|
||||
ASSERT_TRUE(s1.is_stable());
|
||||
ASSERT_TRUE(s2.is_stable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -319,6 +344,8 @@ static bool testAssignCopy()
|
||||
ASSERT_TRUE(s1.size() == 3);
|
||||
ASSERT_TRUE(s2.size() == 3);
|
||||
ASSERT_TRUE(std::strncmp(s2.data(), "abc", 3) == 0);
|
||||
ASSERT_TRUE(s1.is_stable());
|
||||
ASSERT_TRUE(s2.is_stable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -332,6 +359,8 @@ static bool testAssignMove()
|
||||
ASSERT_TRUE(s1.size() == 0);
|
||||
ASSERT_TRUE(s2.size() == 3);
|
||||
ASSERT_TRUE(std::strncmp(s2.data(), "abc", 3) == 0);
|
||||
ASSERT_TRUE(s1.is_stable());
|
||||
ASSERT_TRUE(s2.is_stable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -376,6 +405,7 @@ static bool testOperatorPlusEqual()
|
||||
str += cm::String("g");
|
||||
ASSERT_TRUE(str.size() == 7);
|
||||
ASSERT_TRUE(std::strncmp(str.data(), "abcdefg", 7) == 0);
|
||||
ASSERT_TRUE(str.is_stable());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -742,15 +772,18 @@ static bool testMethod_substr_AtEnd(cm::String str)
|
||||
cm::String substr = str.substr(1);
|
||||
ASSERT_TRUE(substr.data() == str.data() + 1);
|
||||
ASSERT_TRUE(substr.size() == 2);
|
||||
ASSERT_TRUE(!substr.is_stable());
|
||||
|
||||
// c_str() at the end of the buffer does not internally mutate.
|
||||
ASSERT_TRUE(std::strcmp(substr.c_str(), "bc") == 0);
|
||||
ASSERT_TRUE(substr.c_str() == str.data() + 1);
|
||||
ASSERT_TRUE(substr.data() == str.data() + 1);
|
||||
ASSERT_TRUE(substr.size() == 2);
|
||||
ASSERT_TRUE(!substr.is_stable());
|
||||
|
||||
// str() internally mutates.
|
||||
ASSERT_TRUE(substr.str() == "bc");
|
||||
ASSERT_TRUE(substr.is_stable());
|
||||
ASSERT_TRUE(substr.data() != str.data() + 1);
|
||||
ASSERT_TRUE(substr.size() == 2);
|
||||
ASSERT_TRUE(substr.c_str() != str.data() + 1);
|
||||
@ -783,9 +816,11 @@ static bool testMethod_substr_AtStart(cm::String str)
|
||||
ASSERT_TRUE(substr_c != str.data());
|
||||
ASSERT_TRUE(substr.data() != str.data());
|
||||
ASSERT_TRUE(substr.size() == 2);
|
||||
ASSERT_TRUE(substr.is_stable());
|
||||
|
||||
// str() does not need to internally mutate after c_str() did so
|
||||
ASSERT_TRUE(substr.str() == "ab");
|
||||
ASSERT_TRUE(substr.is_stable());
|
||||
ASSERT_TRUE(substr.data() == substr_c);
|
||||
ASSERT_TRUE(substr.size() == 2);
|
||||
ASSERT_TRUE(substr.c_str() == substr_c);
|
||||
@ -795,9 +830,11 @@ static bool testMethod_substr_AtStart(cm::String str)
|
||||
cm::String substr = str.substr(0, 2);
|
||||
ASSERT_TRUE(substr.data() == str.data());
|
||||
ASSERT_TRUE(substr.size() == 2);
|
||||
ASSERT_TRUE(!substr.is_stable());
|
||||
|
||||
// str() internally mutates.
|
||||
ASSERT_TRUE(substr.str() == "ab");
|
||||
ASSERT_TRUE(substr.is_stable());
|
||||
ASSERT_TRUE(substr.data() != str.data());
|
||||
ASSERT_TRUE(substr.size() == 2);
|
||||
ASSERT_TRUE(substr.c_str() != str.data());
|
||||
@ -807,6 +844,7 @@ static bool testMethod_substr_AtStart(cm::String str)
|
||||
ASSERT_TRUE(std::strcmp(substr_c, "ab") == 0);
|
||||
ASSERT_TRUE(substr_c == substr.data());
|
||||
ASSERT_TRUE(substr.size() == 2);
|
||||
ASSERT_TRUE(substr.is_stable());
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1088,6 +1126,7 @@ static bool testAddition()
|
||||
cm::String str;
|
||||
str += "a" + cm::String("b") + 'c';
|
||||
ASSERT_TRUE(str == "abc");
|
||||
ASSERT_TRUE(str.is_stable());
|
||||
}
|
||||
{
|
||||
std::string s;
|
||||
@ -1102,6 +1141,23 @@ static bool testAddition()
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool testStability()
|
||||
{
|
||||
std::cout << "testStability()\n";
|
||||
cm::String str = "abc"_s;
|
||||
ASSERT_TRUE(!str.is_stable());
|
||||
ASSERT_TRUE(str.str_if_stable() == nullptr);
|
||||
str.stabilize();
|
||||
ASSERT_TRUE(str.is_stable());
|
||||
std::string const* str_if_stable = str.str_if_stable();
|
||||
ASSERT_TRUE(str_if_stable != nullptr);
|
||||
ASSERT_TRUE(*str_if_stable == "abc");
|
||||
str.stabilize();
|
||||
ASSERT_TRUE(str.is_stable());
|
||||
ASSERT_TRUE(str.str_if_stable() == str_if_stable);
|
||||
return true;
|
||||
}
|
||||
|
||||
int testString(int /*unused*/, char* /*unused*/ [])
|
||||
{
|
||||
if (!testConstructDefault()) {
|
||||
@ -1284,5 +1340,8 @@ int testString(int /*unused*/, char* /*unused*/ [])
|
||||
if (!testAddition()) {
|
||||
return 1;
|
||||
}
|
||||
if (!testStability()) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user