diff options
author | zhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925> | 2009-09-01 18:53:56 (GMT) |
---|---|---|
committer | zhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925> | 2009-09-01 18:53:56 (GMT) |
commit | 56a2e686e915d483cb22db091140130b23814127 (patch) | |
tree | b37d320ebcd5e50efe61d26ae0e7ed4916cf7334 /include/gtest/internal | |
parent | cb2b1640b277dd9ba2f411cc830682f28bfdaa45 (diff) | |
download | googletest-56a2e686e915d483cb22db091140130b23814127.zip googletest-56a2e686e915d483cb22db091140130b23814127.tar.gz googletest-56a2e686e915d483cb22db091140130b23814127.tar.bz2 |
Enables String to contain NUL (by Zhanyong Wan); Adds scons scripts (by Vlad Losev).
Diffstat (limited to 'include/gtest/internal')
-rw-r--r-- | include/gtest/internal/gtest-string.h | 157 |
1 files changed, 94 insertions, 63 deletions
diff --git a/include/gtest/internal/gtest-string.h b/include/gtest/internal/gtest-string.h index 566a6b5..d36146a 100644 --- a/include/gtest/internal/gtest-string.h +++ b/include/gtest/internal/gtest-string.h @@ -51,6 +51,22 @@ namespace testing { namespace internal { +// Holds data in a String object. We need this class in order to put +// String's data members on the heap instead of on the stack. +// Otherwise tests using many assertions (and thus Strings) in one +// function may need too much stack frame space to compile. +class StringData { + StringData() : c_str_(NULL), length_(0) {} + ~StringData() { delete[] c_str_; } + + private: + friend class String; + + const char* c_str_; + size_t length_; // Length of the string (excluding the terminating + // '\0' character). +}; + // String - a UTF-8 string class. // // We cannot use std::string as Microsoft's STL implementation in @@ -80,19 +96,6 @@ class String { public: // Static utility methods - // Returns the input if it's not NULL, otherwise returns "(null)". - // This function serves two purposes: - // - // 1. ShowCString(NULL) has type 'const char *', instead of the - // type of NULL (which is int). - // - // 2. In MSVC, streaming a null char pointer to StrStream generates - // an access violation, so we need to convert NULL to "(null)" - // before streaming it. - static inline const char* ShowCString(const char* c_str) { - return c_str ? c_str : "(null)"; - } - // Returns the input enclosed in double quotes if it's not NULL; // otherwise returns "(null)". For example, "\"Hello\"" is returned // for input "Hello". @@ -199,27 +202,36 @@ class String { // C'tors - // The default c'tor constructs a NULL string. - String() : c_str_(NULL) {} + // The default c'tor constructs a NULL string, which is represented + // by data_ being NULL. + String() : data_(NULL) {} // Constructs a String by cloning a 0-terminated C string. - String(const char* c_str) : c_str_(NULL) { // NOLINT - *this = c_str; + String(const char* c_str) { // NOLINT + if (c_str == NULL) { + data_ = NULL; + } else { + ConstructNonNull(c_str, strlen(c_str)); + } } // Constructs a String by copying a given number of chars from a - // buffer. E.g. String("hello", 3) will create the string "hel". - String(const char* buffer, size_t len); + // buffer. E.g. String("hello", 3) creates the string "hel", + // String("a\0bcd", 4) creates "a\0bc", String(NULL, 0) creates "", + // and String(NULL, 1) results in access violation. + String(const char* buffer, size_t length) { + ConstructNonNull(buffer, length); + } // The copy c'tor creates a new copy of the string. The two // String objects do not share content. - String(const String& str) : c_str_(NULL) { - *this = str; - } + String(const String& str) : data_(NULL) { *this = str; } // D'tor. String is intended to be a final class, so the d'tor // doesn't need to be virtual. - ~String() { delete[] c_str_; } + ~String() { + delete data_; + } // Allows a String to be implicitly converted to an ::std::string or // ::string, and vice versa. Converting a String containing a NULL @@ -228,21 +240,23 @@ class String { // character to a String will result in the prefix up to the first // NUL character. #if GTEST_HAS_STD_STRING - String(const ::std::string& str) : c_str_(NULL) { *this = str.c_str(); } + String(const ::std::string& str) { + ConstructNonNull(str.c_str(), str.length()); + } - operator ::std::string() const { return ::std::string(c_str_); } + operator ::std::string() const { return ::std::string(c_str(), length()); } #endif // GTEST_HAS_STD_STRING #if GTEST_HAS_GLOBAL_STRING - String(const ::string& str) : c_str_(NULL) { *this = str.c_str(); } + String(const ::string& str) { + ConstructNonNull(str.c_str(), str.length()); + } - operator ::string() const { return ::string(c_str_); } + operator ::string() const { return ::string(c_str(), length()); } #endif // GTEST_HAS_GLOBAL_STRING // Returns true iff this is an empty string (i.e. ""). - bool empty() const { - return (c_str_ != NULL) && (*c_str_ == '\0'); - } + bool empty() const { return (c_str() != NULL) && (length() == 0); } // Compares this with another String. // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 @@ -251,19 +265,15 @@ class String { // Returns true iff this String equals the given C string. A NULL // string and a non-NULL string are considered not equal. - bool operator==(const char* c_str) const { - return CStringEquals(c_str_, c_str); - } + bool operator==(const char* c_str) const { return Compare(c_str) == 0; } - // Returns true iff this String is less than the given C string. A NULL - // string is considered less than "". + // Returns true iff this String is less than the given String. A + // NULL string is considered less than "". bool operator<(const String& rhs) const { return Compare(rhs) < 0; } // Returns true iff this String doesn't equal the given C string. A NULL // string and a non-NULL string are considered not equal. - bool operator!=(const char* c_str) const { - return !CStringEquals(c_str_, c_str); - } + bool operator!=(const char* c_str) const { return !(*this == c_str); } // Returns true iff this String ends with the given suffix. *Any* // String is considered to end with a NULL or empty suffix. @@ -273,45 +283,66 @@ class String { // case. Any String is considered to end with a NULL or empty suffix. bool EndsWithCaseInsensitive(const char* suffix) const; - // Returns the length of the encapsulated string, or -1 if the + // Returns the length of the encapsulated string, or 0 if the // string is NULL. - int GetLength() const { - return c_str_ ? static_cast<int>(strlen(c_str_)) : -1; - } + size_t length() const { return (data_ == NULL) ? 0 : data_->length_; } // Gets the 0-terminated C string this String object represents. // The String object still owns the string. Therefore the caller // should NOT delete the return value. - const char* c_str() const { return c_str_; } - - // Sets the 0-terminated C string this String object represents. - // The old string in this object is deleted, and this object will - // own a clone of the input string. This function copies only up to - // length bytes (plus a terminating null byte), or until the first - // null byte, whichever comes first. - // - // This function works even when the c_str parameter has the same - // value as that of the c_str_ field. - void Set(const char* c_str, size_t length); + const char* c_str() const { return (data_ == NULL) ? NULL : data_->c_str_; } // Assigns a C string to this object. Self-assignment works. - const String& operator=(const char* c_str); + const String& operator=(const char* c_str) { return *this = String(c_str); } // Assigns a String object to this object. Self-assignment works. - const String& operator=(const String &rhs) { - *this = rhs.c_str_; + const String& operator=(const String& rhs) { + if (this != &rhs) { + delete data_; + data_ = NULL; + if (rhs.data_ != NULL) { + ConstructNonNull(rhs.data_->c_str_, rhs.data_->length_); + } + } + return *this; } private: - const char* c_str_; -}; + // Constructs a non-NULL String from the given content. This + // function can only be called when data_ has not been allocated. + // ConstructNonNull(NULL, 0) results in an empty string (""). + // ConstructNonNull(NULL, non_zero) is undefined behavior. + void ConstructNonNull(const char* buffer, size_t length) { + data_ = new StringData; + char* const str = new char[length + 1]; + memcpy(str, buffer, length); + str[length] = '\0'; + data_->c_str_ = str; + data_->length_ = length; + } -// Streams a String to an ostream. -inline ::std::ostream& operator <<(::std::ostream& os, const String& str) { - // We call String::ShowCString() to convert NULL to "(null)". - // Otherwise we'll get an access violation on Windows. - return os << String::ShowCString(str.c_str()); + // Points to the representation of the String. A NULL String is + // represented by data_ == NULL. + StringData* data_; +}; // class String + +// Streams a String to an ostream. Each '\0' character in the String +// is replaced with "\\0". +inline ::std::ostream& operator<<(::std::ostream& os, const String& str) { + if (str.c_str() == NULL) { + os << "(null)"; + } else { + const char* const c_str = str.c_str(); + for (size_t i = 0; i != str.length(); i++) { + if (c_str[i] == '\0') { + os << "\\0"; + } else { + os << c_str[i]; + } + } + } + return os; } // Gets the content of the StrStream's buffer as a String. Each '\0' |