From fa1bb779e5a1881fe16fb7d3dd1c3ec53576a023 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Fri, 25 Jul 2014 18:15:10 -0700 Subject: [PATCH 1/2] Add explicit string literal overload to try to help Coverity (and avoid a strlen call to boot). --- Sources/Plasma/CoreLib/plString.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Sources/Plasma/CoreLib/plString.h b/Sources/Plasma/CoreLib/plString.h index 18e7b534..8004d32f 100644 --- a/Sources/Plasma/CoreLib/plString.h +++ b/Sources/Plasma/CoreLib/plString.h @@ -254,6 +254,13 @@ public: */ plString(const char *cstr, size_t size = STRLEN_AUTO) { IConvertFromUtf8(cstr, size); } + /** Construct a plString from a string literal. + * \note This constructor expects the input to be UTF-8 encoded. For + * conversion from ISO-8859-1 8-bit data, use FromIso8859_1(). + */ + template + plString(const char (&literal)[_Sz]) { IConvertFromUtf8(literal, _Sz); } + /** Copy constructor. */ plString(const plString ©) : fUtf8Buffer(copy.fUtf8Buffer) { } @@ -269,6 +276,10 @@ public: /** Assignment operator. Same as plString(const char *). */ plString &operator=(const char *cstr) { IConvertFromUtf8(cstr, STRLEN_AUTO); return *this; } + /** Assignment operator. Same as plString(const char (&)[_Sz]). */ + template + plString &operator=(const char (&literal)[_Sz]) { IConvertFromUtf8(literal, _Sz); return *this; } + /** Assignment operator. Same as plString(const plString &). */ plString &operator=(const plString ©) { fUtf8Buffer = copy.fUtf8Buffer; return *this; } From 5ed3e3205c3ba9eb087086e44f6eff027357e889 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Fri, 25 Jul 2014 18:20:25 -0700 Subject: [PATCH 2/2] Add move semantics to plString and plStringStream --- Sources/Plasma/CoreLib/plString.cpp | 24 ++++++++--- Sources/Plasma/CoreLib/plString.h | 63 ++++++++++++++++++++++++++--- 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/Sources/Plasma/CoreLib/plString.cpp b/Sources/Plasma/CoreLib/plString.cpp index af59238d..6d11502f 100644 --- a/Sources/Plasma/CoreLib/plString.cpp +++ b/Sources/Plasma/CoreLib/plString.cpp @@ -88,14 +88,12 @@ void plString::IConvertFromUtf8(const char *utf8, size_t size) operator=(plStringBuffer(utf8, size)); } -plString &plString::operator=(const plStringBuffer &init) -{ - fUtf8Buffer = init; - #ifdef _DEBUG // Check to make sure the string is actually valid UTF-8 - const char *sp = fUtf8Buffer.GetData(); - while (sp < fUtf8Buffer.GetData() + fUtf8Buffer.GetSize()) { +static void _check_utf8_buffer(const plStringBuffer &buffer) +{ + const char *sp = buffer.GetData(); + while (sp < buffer.GetData() + buffer.GetSize()) { unsigned char unichar = *sp++; if ((unichar & 0xF8) == 0xF0) { // Four bytes @@ -115,8 +113,22 @@ plString &plString::operator=(const plStringBuffer &init) hsAssert(0, "UTF-8 character out of range"); } } +} +#else +# define _check_utf8_buffer(buffer) NULL_STMT #endif +plString &plString::operator=(const plStringBuffer &init) +{ + fUtf8Buffer = init; + _check_utf8_buffer(fUtf8Buffer); + return *this; +} + +plString &plString::operator=(plStringBuffer &&init) +{ + fUtf8Buffer = std::move(init); + _check_utf8_buffer(fUtf8Buffer); return *this; } diff --git a/Sources/Plasma/CoreLib/plString.h b/Sources/Plasma/CoreLib/plString.h index 8004d32f..0fb50769 100644 --- a/Sources/Plasma/CoreLib/plString.h +++ b/Sources/Plasma/CoreLib/plString.h @@ -128,6 +128,13 @@ public: fData->AddRef(); } + /** Move constructor */ + plStringBuffer(plStringBuffer<_Ch> &&move) : fSize(move.fSize) + { + memcpy(fShort, move.fShort, sizeof(fShort)); + move.fSize = 0; + } + /** Construct a string buffer which holds a COPY of the \a data, up to * \a size characters. The terminating '\0' is added automatically, * meaning this constructor is safe to use on buffers which are not @@ -154,7 +161,7 @@ public: } /** Assignment operator. Changes the reference to point to the - * copied buffer in \a copy. + * buffer in \a copy. */ plStringBuffer<_Ch> &operator=(const plStringBuffer<_Ch> ©) { @@ -168,6 +175,18 @@ public: return *this; } + /** Move assignment operator */ + plStringBuffer<_Ch> &operator=(plStringBuffer<_Ch> &&move) + { + if (IHaveACow()) + fData->DecRef(); + + memcpy(fShort, move.fShort, sizeof(fShort)); + fSize = move.fSize; + move.fSize = 0; + return *this; + } + /** Returns a pointer to the referenced string buffer. */ const _Ch *GetData() const { return IHaveACow() ? fData->fStringData : fShort; } @@ -235,14 +254,15 @@ private: void IConvertFromUtf32(const UniChar *ustr, size_t size); void IConvertFromIso8859_1(const char *astr, size_t size); +public: // Constructing and comparing with nil or nullptr won't break plString, // but it's preferred not to do so with the constants. That is to say, // you can construct with a const char * which points to null, but // don't actually write `plString foo = nil;` - plString(std::nullptr_t) { } - void operator=(std::nullptr_t) { } - void operator==(std::nullptr_t) const { } - void operator!=(std::nullptr_t) const { } + plString(std::nullptr_t) = delete; + void operator=(std::nullptr_t) = delete; + void operator==(std::nullptr_t) const = delete; + void operator!=(std::nullptr_t) const = delete; public: /** Construct a valid, empty string. */ @@ -264,12 +284,18 @@ public: /** Copy constructor. */ plString(const plString ©) : fUtf8Buffer(copy.fUtf8Buffer) { } + /** Move constructor. */ + plString(plString &&move) : fUtf8Buffer(std::move(move.fUtf8Buffer)) { } + /** Copy constructor from plStringBuffer. * \note This constructor expects the input to be UTF-8 encoded. For * conversion from ISO-8859-1 8-bit data, use FromIso8859_1(). */ plString(const plStringBuffer &init) { operator=(init); } + /** Move constructor from plStringBuffer. */ + plString(plStringBuffer &&init) { operator=(std::move(init)); } + /** Construct a string from expanded Unicode data. */ plString(const plUnicodeBuffer &init) { IConvertFromUtf32(init.GetData(), init.GetSize()); } @@ -283,9 +309,15 @@ public: /** Assignment operator. Same as plString(const plString &). */ plString &operator=(const plString ©) { fUtf8Buffer = copy.fUtf8Buffer; return *this; } + /** Assignment operator. Same as plString(plString &&). */ + plString &operator=(plString &&move) { fUtf8Buffer = std::move(move.fUtf8Buffer); return *this; } + /** Assignment operator. Same as plString(const plStringBuffer &). */ plString &operator=(const plStringBuffer &init); + /** Assignment operator. Same as plString(plStringBuffer &&). */ + plString &operator=(plStringBuffer &&init); + /** Assignment operator. Same as plString(const plUnicodeBuffer &). */ plString &operator=(const plUnicodeBuffer &init) { IConvertFromUtf32(init.GetData(), init.GetSize()); return *this; } @@ -685,6 +717,27 @@ public: /** Destructor, frees any allocated heap memory owned by the stream. */ ~plStringStream() { if (ICanHasHeap()) delete [] fBuffer; } + plStringStream(const plStringStream &) = delete; + plStringStream &operator=(const plStringStream &) = delete; + + /** Move operator */ + plStringStream(plStringStream &&move) + : fBufSize(move.fBufSize), fLength(move.fLength) + { + memcpy(fShort, move.fShort, sizeof(fShort)); + move.fBufSize = 0; + } + + /** Move assignment operator. */ + plStringStream &operator=(plStringStream &&move) + { + memcpy(fShort, move.fShort, sizeof(fShort)); + fBufSize = move.fBufSize; + fLength = move.fLength; + move.fBufSize = 0; + return *this; + } + /** Append string data to the end of the stream. */ plStringStream &append(const char *data, size_t length);