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);