From a8dee23ea037bca91d23eee891ac5757cf143e73 Mon Sep 17 00:00:00 2001 From: Stefano Ceccherini Date: Fri, 10 Jan 2003 10:19:56 +0000 Subject: [PATCH] A fix for a Replace function, some checks which makes the code more robust, some style changes, some more comments. Started to document the class with Doxygen comments. (I made too many changes to keep the file local :) git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2399 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kits/support/String.cpp | 803 +++++++++++++++++++++++++++++------- 1 file changed, 659 insertions(+), 144 deletions(-) diff --git a/src/kits/support/String.cpp b/src/kits/support/String.cpp index 5105ed8d9f..b7e0447f20 100644 --- a/src/kits/support/String.cpp +++ b/src/kits/support/String.cpp @@ -27,35 +27,62 @@ //------------------------------------------------------------------------------ // Standard Includes ----------------------------------------------------------- -#include #include #include #include // System Includes ------------------------------------------------------------- -#define DEBUG 1 #include #include -#include // Temporary Includes #include "string_helper.h" -/*---- Construction --------------------------------------------------------*/ + +#define ENABLE_INLINES 0 // Set this to 1 to make some private methods inline + + +/*! + \class BString + \brief String class supporting common string operations + + BString is a string allocation and manipulation class. The object + takes care to allocate and free memory for you, so it will always be + "big enough" to store your strings. + + \author Stefano Ceccherini +*/ + +/*! \var char* BString::_privateData + \brief BString's storage for data +*/ + +// constructor +/*! \brief Creates an uninitialized BString. +*/ BString::BString() :_privateData(NULL) { } +// constructor +/*! \brief Creates a BString and initializes it to the given string. + \param str Pointer to a NULL terminated string. +*/ BString::BString(const char* str) :_privateData(NULL) { - if (str) + if (str!= NULL) _Init(str, strlen(str)); } +// copy constructor +/*! \brief Creates a BString and makes it a copy of the supplied one. + \param string the BString object to be copied. +*/ BString::BString(const BString &string) :_privateData(NULL) { @@ -63,17 +90,28 @@ BString::BString(const BString &string) } +// constructor +/*! \brief Creates a BString and initializes it to the given string. + \param str Pointer to a NULL terminated string. + \param maxLength The amount of characters you want to copy from the original + string. +*/ BString::BString(const char *str, int32 maxLength) :_privateData(NULL) { - if (str) { + if (str != NULL) + { int32 len = (int32)strlen(str); - _Init(str, min(len, maxLength)); + _Init(str, min_c(len, maxLength)); } } -/*---- Destruction ---------------------------------------------------------*/ +// destructor +/*! \brief Frees all resources associated with the object. + + Frees the memory allocated by the BString object. +*/ BString::~BString() { if (_privateData) @@ -82,12 +120,42 @@ BString::~BString() /*---- Access --------------------------------------------------------------*/ +// String, implemented inline in the header +/*! \fn const char* BString::String() const + \brief Returns a pointer to the object string, NULL terminated. + + Returns a pointer to the object string, guaranteed to be NULL + terminated. You can't modify or free the pointer. Once the BString + object is deleted, the pointer becomes invalid. + + \return A pointer to the object string. +*/ + + +// Length, implemented inline in the header +/*! \fn int32 BString::Length() const + \brief Returns the length of the string, measured in bytes. + \return The length of the string, measured in bytes. +*/ + + +// CountChars +/*! \brief Returns the length of the object measured in characters. + \return An integer which is the number of characters in the string. + + Counts the number of UTF8 characters contained in the string. +*/ int32 BString::CountChars() const { int32 count = 0; - const char *ptr = String(); - + + const char *start = _privateData; + + /* String's end. This way we don't have to check for '\0' */ + /* but just compare two pointers (which should be faster) */ + const char *end = _privateData + Length(); + #if 0 // ejaesler: Left in memoriam of one man's foolish disregard for the // maxim "Premature optimization is the root of all evil" @@ -99,31 +167,46 @@ BString::CountChars() const count++; } #endif - while (*ptr++) + + while (start++ != end) { count++; // Jump to next UTF8 character - for (; (*ptr & 0xc0) == 0x80; ptr++); + for (; (*start & 0xc0) == 0x80; start++); } + return count; } /*---- Assignment ----------------------------------------------------------*/ +// equal operator +/*! \brief Makes a copy of the given BString object. + \param string The string object to copy. + \return + The function always returns \c *this . +*/ BString& BString::operator=(const BString &string) { - _DoAssign(string.String(), string.Length()); + if (&string != this) // Avoid auto-assignment + _DoAssign(string.String(), string.Length()); return *this; } +// equal operator +/*! \brief Re-initializes the object to the given string. + \param str Pointer to a string. + \return + The function always returns \c *this . +*/ BString& BString::operator=(const char *str) { - if (str) + if (str != NULL) _DoAssign(str, strlen(str)); else _GrowBy(-Length()); // Empties the string @@ -132,41 +215,78 @@ BString::operator=(const char *str) } +// equal operator +/*! \brief Re-initializes the object to the given character. + \param c The character which you want to initialize the string to. + \return + The function always returns \c *this . +*/ BString& BString::operator=(char c) { - _DoAssign(&c, 1); + int32 curLen = Length(); + + if (curLen != 1) + _GrowBy(1 - curLen); + _privateData[0] = c; + return *this; } +// SetTo +/*! \brief Re-initializes the object to the given string. + \param str Pointer to a string. + \param length Amount of characters to copy from the original string. + \return + The function always returns \c *this . +*/ BString& BString::SetTo(const char *str, int32 length) { - if (str) { + if (str != NULL) + { int32 len = (int32)strlen(str); - _DoAssign(str, min(length, len)); - } else + _DoAssign(str, min_c(length, len)); + } + else _GrowBy(-Length()); // Empties the string return *this; } +// SetTo +/*! \brief Makes a copy of the given BString object. + \param from The string object to copy. + \return + The function always returns \c *this . +*/ BString& BString::SetTo(const BString &from) { - _DoAssign(from.String(), from.Length()); + if (&from != this) // Avoid auto-assignment + _DoAssign(from.String(), from.Length()); return *this; } +// Adopt +/*! \brief Adopt's data of the given BString object, freeing the original object. + \param from The string object to adopt. + \return + The function always returns \c *this . +*/ BString& BString::Adopt(BString &from) { + if (&from == this) // Avoid auto-adoption + return *this; + if (_privateData) free(_privateData - sizeof(int32)); + /* "steal" the data from the given BString */ _privateData = from._privateData; from._privateData = NULL; @@ -174,20 +294,39 @@ BString::Adopt(BString &from) } +// SetTo +/*! \brief Makes a copy of the given BString object. + \param from The string object to copy. + \param length Amount of characters to copy from the original BString. + \return + The function always returns \c *this . +*/ BString& BString::SetTo(const BString &string, int32 length) { - _DoAssign(string.String(), min(length, string.Length())); + if (&string != this) // Avoid auto-assignment + _DoAssign(string.String(), min_c(length, string.Length())); return *this; } +// Adopt +/*! \brief Adopt's data of the given BString object, freeing the original object. + \param from The string object to adopt. + \param length Amount of characters to get from the original BString. + \return + The function always returns \c *this . +*/ BString& BString::Adopt(BString &from, int32 length) { + if (&from == this) // Avoid auto-adoption + return *this; + if (_privateData) free(_privateData - sizeof(int32)); + /* "steal" the data from the given BString */ _privateData = from._privateData; from._privateData = NULL; @@ -198,10 +337,21 @@ BString::Adopt(BString &from, int32 length) } +// SetTo +/*! \brief Initializes the object to a string composed by a character you specify. + \param c The character you want to initialize the BString. + \param count The number of characters you want the BString to be composed by. + \return + The function always returns \c *this . +*/ BString& BString::SetTo(char c, int32 count) { - _GrowBy(count - Length()); + int32 curLen = Length(); + + if (curLen != count) + _GrowBy(count - curLen); + memset(_privateData, c, count); return *this; @@ -209,7 +359,16 @@ BString::SetTo(char c, int32 count) /*---- Substring copying ---------------------------------------------------*/ -BString &BString::CopyInto(BString &into, int32 fromOffset, int32 length) const + +// CopyInto +/*! \brief Copy the BString data (or part of it) into another BString. + \param into The BString where to copy the object. + \param fromOffset The offset (zero based) where to begin the copy + \param length The amount of bytes to copy. + \return This function always returns *this . +*/ +BString & +BString::CopyInto(BString &into, int32 fromOffset, int32 length) const { if (&into != this) into.SetTo(String() + fromOffset, length); @@ -217,54 +376,92 @@ BString &BString::CopyInto(BString &into, int32 fromOffset, int32 length) const } +// CopyInto +/*! \brief Copy the BString data (or part of it) into the supplied buffer. + \param into The buffer where to copy the object. + \param fromOffset The offset (zero based) where to begin the copy + \param length The amount of bytes to copy. +*/ void BString::CopyInto(char *into, int32 fromOffset, int32 length) const { - if (into) { + if (into != NULL) + { int32 len = Length() - fromOffset; - len = min(len, length); + len = min_c(len, length); memcpy(into, _privateData + fromOffset, len); } } /*---- Appending -----------------------------------------------------------*/ +// plus operator +/*! \brief Appends the given string to the object. + \param str A pointer to the string to append. + \return This function always returns *this . +*/ BString& BString::operator+=(const char *str) { - if (str) + if (str != NULL) _DoAppend(str, strlen(str)); return *this; } +// plus operator +/*! \brief Appends the given character to the object. + \param c The character to append. + \return This function always returns *this . +*/ BString& BString::operator+=(char c) { - _DoAppend(&c, 1); + _GrowBy(1); + _privateData[Length() - 1] = c; + return *this; } +// Append +/*! \brief Appends the given BString to the object. + \param string The BString to append. + \param length The maximum bytes to get from the original object. + \return This function always returns *this . +*/ BString& BString::Append(const BString &string, int32 length) { - _DoAppend(string.String(), min(length, string.Length())); + _DoAppend(string.String(), min_c(length, string.Length())); return *this; } +// Append +/*! \brief Appends the given string to the object. + \param str A pointer to the string to append. + \param length The maximum bytes to get from the original string. + \return This function always returns *this . +*/ BString& BString::Append(const char *str, int32 length) { - if (str) { + if (str != NULL) + { int32 len = (int32)strlen(str); - _DoAppend(str, min(len, length)); + _DoAppend(str, min_c(len, length)); } return *this; } +// Append +/*! \brief Appends the given character to the object. + \param c The character to append. + \param count The number of characters to append. + \return This function always returns *this . +*/ BString& BString::Append(char c, int32 count) { @@ -277,15 +474,25 @@ BString::Append(char c, int32 count) /*---- Prepending ----------------------------------------------------------*/ +// Prepend +/*! \brief Prepends the given string to the object. + \param str A pointer to the string to prepend. + \return This function always returns *this . +*/ BString& BString::Prepend(const char *str) { - if (str) + if (str != NULL) _DoPrepend(str, strlen(str)); return *this; } +// Prepend +/*! \brief Prepends the given BString to the object. + \param string The BString object to prepend. + \return This function always returns *this . +*/ BString& BString::Prepend(const BString &string) { @@ -295,26 +502,45 @@ BString::Prepend(const BString &string) } +// Prepend +/*! \brief Prepends the given string to the object. + \param str A pointer to the string to prepend. + \param length The maximum amount of bytes to get from the string. + \return This function always returns *this . +*/ BString& BString::Prepend(const char *str, int32 length) { - if (str) { + if (str != NULL) + { int32 len = (int32)strlen(str); - _DoPrepend(str, min(len, length)); + _DoPrepend(str, min_c(len, length)); } return *this; } +// Prepend +/*! \brief Prepends the given BString to the object. + \param string The BString object to prepend. + \param len The maximum amount of bytes to get from the BString. + \return This function always returns *this . +*/ BString& BString::Prepend(const BString &string, int32 len) { if (&string != this) - _DoPrepend(string.String(), min(len, string.Length())); + _DoPrepend(string.String(), min_c(len, string.Length())); return *this; } +// Prepend +/*! \brief Prepends the given character to the object. + \param c The character to prepend. + \param count The amount of characters to prepend. + \return This function always returns *this . +*/ BString& BString::Prepend(char c, int32 count) { @@ -326,11 +552,19 @@ BString::Prepend(char c, int32 count) /*---- Inserting ----------------------------------------------------------*/ +// Insert +/*! \brief Inserts the given string at the given position into the object's data. + \param str A pointer to the string to insert. + \param pos The offset into the BString's data where to insert the string. + \return This function always returns *this . +*/ BString& BString::Insert(const char *str, int32 pos) { - if (str) { - if (pos < 0) { + if (str != NULL) + { + if (pos < 0) + { str -= pos; pos = 0; } @@ -341,29 +575,47 @@ BString::Insert(const char *str, int32 pos) } +// Insert +/*! \brief Inserts the given string at the given position into the object's data. + \param str A pointer to the string to insert. + \param length The amount of bytes to insert. + \param pos The offset into the BString's data where to insert the string. + \return This function always returns *this . +*/ BString& BString::Insert(const char *str, int32 length, int32 pos) { - if (str) { - if (pos < 0) { + if (str != NULL) + { + if (pos < 0) + { str -= pos; pos = 0; } int32 len = (int32)strlen(str); - len = min(len, length); - _privateData = _OpenAtBy(pos, len); + len = min_c(len, length); + _OpenAtBy(pos, len); memcpy(_privateData + pos, str, len); } return *this; } +// Insert +/*! \brief Inserts the given string at the given position into the object's data. + \param str A pointer to the string to insert. + \param fromOffset + \param length The amount of bytes to insert. + \param pos The offset into the BString's data where to insert the string. + \return This function always returns *this . +*/ BString& BString::Insert(const char *str, int32 fromOffset, int32 length, int32 pos) { - if (str) { + if (str != NULL) + { int32 len = (int32)strlen(str); - len = min(len - fromOffset, length); + len = min_c(len - fromOffset, length); _privateData = _OpenAtBy(pos, len); memcpy(_privateData + pos, str + fromOffset, len); } @@ -371,6 +623,12 @@ BString::Insert(const char *str, int32 fromOffset, int32 length, int32 pos) } +// Insert +/*! \brief Inserts the given BString at the given position into the object's data. + \param string The BString object to insert. + \param pos The offset into the BString's data where to insert the string. + \return This function always returns *this . +*/ BString& BString::Insert(const BString &string, int32 pos) { @@ -380,6 +638,13 @@ BString::Insert(const BString &string, int32 pos) } +// Insert +/*! \brief Inserts the given BString at the given position into the object's data. + \param string The BString object to insert. + \param length The amount of bytes to insert. + \param pos The offset into the BString's data where to insert the string. + \return This function always returns *this . +*/ BString& BString::Insert(const BString &string, int32 length, int32 pos) { @@ -389,6 +654,14 @@ BString::Insert(const BString &string, int32 length, int32 pos) } +// Insert +/*! \brief Inserts the given string at the given position into the object's data. + \param string The BString object to insert. + \param fromOffset + \param length The amount of bytes to insert. + \param pos The offset into the BString's data where to insert the string. + \return This function always returns *this . +*/ BString& BString::Insert(const BString &string, int32 fromOffset, int32 length, int32 pos) { @@ -398,6 +671,13 @@ BString::Insert(const BString &string, int32 fromOffset, int32 length, int32 pos } +// Insert +/*! \brief Inserts the given character at the given position into the object's data. + \param c The character to insert. + \param count The amount of bytes to insert. + \param pos The offset into the BString's data where to insert the string. + \return This function always returns *this . +*/ BString& BString::Insert(char c, int32 count, int32 pos) { @@ -409,23 +689,38 @@ BString::Insert(char c, int32 count, int32 pos) /*---- Removing -----------------------------------------------------------*/ +// Truncate +/*! \brief Truncate the string to the new length. + \param newLength The new lenght of the string. + \param lazy Currently unused. (?) + \return This function always returns *this . +*/ BString& -BString::Truncate(int32 newLength, bool lazy = true) +BString::Truncate(int32 newLength, bool lazy) { if (newLength < 0) - return *this; + newLength = 0; + + int32 curLen = Length(); - if (newLength < Length()) { + if (newLength < curLen) + { //TODO: Implement lazy truncate? - _privateData = _GrowBy(newLength - Length()); //Negative - _privateData[Length()] = '\0'; + _GrowBy(newLength - curLen); //Negative + _privateData[newLength] = '\0'; } return *this; } +// Remove +/*! \brief Removes some bytes, starting at the given offset + \param from The offset from which you want to start removing + \param length The number of bytes to remove + \return This function always returns *this . +*/ BString& BString::Remove(int32 from, int32 length) { @@ -434,30 +729,45 @@ BString::Remove(int32 from, int32 length) } +// Remove +/*! \brief Removes the first occurrence of the given BString. + \param string The BString to remove. + \return This function always returns *this . +*/ BString& BString::RemoveFirst(const BString &string) { int32 pos = _ShortFindAfter(string.String(), string.Length()); if (pos >= 0) - _privateData = _ShrinkAtBy(pos, string.Length()); + _ShrinkAtBy(pos, string.Length()); return *this; } +// Remove +/*! \brief Removes the last occurrence of the given BString. + \param string The BString to remove. + \return This function always returns *this . +*/ BString& BString::RemoveLast(const BString &string) { int32 pos = _FindBefore(string.String(), Length(), string.Length()); if (pos >= 0) - _privateData = _ShrinkAtBy(pos, string.Length()); + _ShrinkAtBy(pos, string.Length()); return *this; } +// Remove +/*! \brief Removes all occurrences of the given BString. + \param string The BString to remove. + \return This function always returns *this . +*/ BString& BString::RemoveAll(const BString &string) { @@ -469,10 +779,16 @@ BString::RemoveAll(const BString &string) } +// Remove +/*! \brief Removes the first occurrence of the given string. + \param str A pointer to the string to remove. + \return This function always returns *this . +*/ BString& BString::RemoveFirst(const char *str) { - if (str) { + if (str != NULL) + { int32 pos = _ShortFindAfter(str, strlen(str)); if (pos >= 0) _ShrinkAtBy(pos, strlen(str)); @@ -481,10 +797,16 @@ BString::RemoveFirst(const char *str) } +// Remove +/*! \brief Removes the last occurrence of the given string. + \param str A pointer to the string to remove. + \return This function always returns *this . +*/ BString& BString::RemoveLast(const char *str) { - if (str) { + if (str != NULL) + { int32 len = strlen(str); int32 pos = _FindBefore(str, Length(), len); if (pos >= 0) @@ -494,23 +816,35 @@ BString::RemoveLast(const char *str) } +// Remove +/*! \brief Removes all occurrences of the given string. + \param str A pointer to the string to remove. + \return This function always returns *this . +*/ BString& BString::RemoveAll(const char *str) { - if (str) { + if (str != NULL) + { int32 pos; int32 len = strlen(str); - while ((pos = _ShortFindAfter(str, len)) >= 0) + while ((pos = _ShortFindAfter(str, len)) >= 0) _ShrinkAtBy(pos, len); } return *this; } +// Remove +/*! \brief Removes all the characters specified. + \param setOfCharsToRemove The set of characters to remove. + \return This function always returns *this . +*/ BString& BString::RemoveSet(const char *setOfCharsToRemove) { - if (setOfCharsToRemove) { + if (setOfCharsToRemove != NULL) + { int32 pos; while ((pos = strcspn(String(), setOfCharsToRemove)) < Length()) _privateData = _ShrinkAtBy(pos, 1); @@ -519,12 +853,22 @@ BString::RemoveSet(const char *setOfCharsToRemove) } +// MoveInto +/*! \brief Move the BString data (or part of it) into another BString. + \param into The BString where to move the object. + \param from The offset (zero based) where to begin the move + \param length The amount of bytes to move. + \return This function always returns *this . +*/ BString& BString::MoveInto(BString &into, int32 from, int32 length) { + if (&into == this) + return *this; + int32 len = Length() - from; - len = min(len, length); + len = min_c(len, length); into.SetTo(String() + from, length); @@ -535,10 +879,17 @@ BString::MoveInto(BString &into, int32 from, int32 length) } +// MoveInto +/*! \brief Move the BString data (or part of it) into the given buffer. + \param into The buffer where to move the object. + \param from The offset (zero based) where to begin the move + \param length The amount of bytes to move. +*/ void BString::MoveInto(char *into, int32 from, int32 length) { - if (into) { + if (into != NULL) + { memcpy(into, String() + from, length); if (from + length <= Length()) _privateData = _ShrinkAtBy(from, length); @@ -641,6 +992,12 @@ BString::ICompare(const char *str, int32 n) const /*---- Searching -----------------------------------------------------------*/ +// FindFirst +/*! \brief Find the first occurrence of the given BString. + \param string The BString to search for. + \return The offset(zero based) into the data + where the given BString has been found. +*/ int32 BString::FindFirst(const BString &string) const { @@ -648,6 +1005,12 @@ BString::FindFirst(const BString &string) const } +// FindFirst +/*! \brief Find the first occurrence of the given string. + \param string The string to search for. + \return The offset(zero based) into the data + where the given string has been found. +*/ int32 BString::FindFirst(const char *string) const { @@ -657,6 +1020,14 @@ BString::FindFirst(const char *string) const } +// FindFirst +/*! \brief Find the first occurrence of the given BString, + starting from the given offset. + \param string The BString to search for. + \param fromOffset The offset where to start the search. + \return An integer which is the offset(zero based) into the data + where the given BString has been found. +*/ int32 BString::FindFirst(const BString &string, int32 fromOffset) const { @@ -664,6 +1035,14 @@ BString::FindFirst(const BString &string, int32 fromOffset) const } +// FindFirst +/*! \brief Find the first occurrence of the given string, + starting from the given offset. + \param string The string to search for. + \param fromOffset The offset where to start the search. + \return The offset(zero based) into the data + where the given string has been found. +*/ int32 BString::FindFirst(const char *string, int32 fromOffset) const { @@ -673,24 +1052,62 @@ BString::FindFirst(const char *string, int32 fromOffset) const } +// FindFirst +/*! \brief Find the first occurrence of the given character. + \param c The character to search for. + \return The offset(zero based) into the data + where the given character has been found. +*/ int32 BString::FindFirst(char c) const -{ - char tmp[2] = { c, '\0' }; +{ + char *start = _privateData; + char *end = _privateData + Length(); /* String's end */ - return _ShortFindAfter(tmp, 1); + /* Scans the string until we found the character, */ + /* or we hit the string's end */ + while(start != end && *start != c) + start++; + + if (start == end) + return B_ERROR; + + return start - _privateData; } +// FindFirst +/*! \brief Find the first occurrence of the given character, + starting from the given offset. + \param c The character to search for. + \param fromOffset The offset where to start the search. + \return The offset(zero based) into the data + where the given character has been found. +*/ int32 BString::FindFirst(char c, int32 fromOffset) const { - char tmp[2] = { c, '\0' }; + char *start = _privateData + fromOffset; + char *end = _privateData + Length(); /* String's end */ - return _FindAfter(tmp, fromOffset, 1); + /* Scans the string until we found the character, */ + /* or we hit the string's end */ + while(start < end && *start != c) + start++; + + if (start >= end) + return B_ERROR; + + return start - _privateData; } +// FindLast +/*! \brief Find the last occurrence of the given BString. + \param string The BString to search for. + \return The offset(zero based) into the data + where the given BString has been found. +*/ int32 BString::FindLast(const BString &string) const { @@ -698,6 +1115,12 @@ BString::FindLast(const BString &string) const } +// FindLast +/*! \brief Find the last occurrence of the given string. + \param string The string to search for. + \return The offset(zero based) into the data + where the given string has been found. +*/ int32 BString::FindLast(const char *string) const { @@ -707,6 +1130,14 @@ BString::FindLast(const char *string) const } +// FindLast +/*! \brief Find the last occurrence of the given BString, + starting from the given offset, and going backwards. + \param string The BString to search for. + \param beforeOffset The offset where to start the search. + \return An integer which is the offset(zero based) into the data + where the given BString has been found. +*/ int32 BString::FindLast(const BString &string, int32 beforeOffset) const { @@ -714,6 +1145,13 @@ BString::FindLast(const BString &string, int32 beforeOffset) const } +// FindLast +/*! \brief Find the last occurrence of the given string, + starting from the given offset, and going backwards. + \param string The string to search for. + \return The offset(zero based) into the data + where the given string has been found. +*/ int32 BString::FindLast(const char *string, int32 beforeOffset) const { @@ -723,21 +1161,53 @@ BString::FindLast(const char *string, int32 beforeOffset) const } +// FindLast +/*! \brief Find the last occurrence of the given character. + \param c The character to search for. + \return The offset(zero based) into the data + where the given character has been found. +*/ int32 BString::FindLast(char c) const { - char tmp[2] = { c, '\0' }; + char *start = _privateData; + char *end = _privateData + Length(); /* String's end */ - return _FindBefore(tmp, Length(), 1); + /* Scans the string backwards until we found the character, */ + /* or we reach the string's start */ + while(end != start && *end != c) + end--; + + if (end == start) + return B_ERROR; + + return end - _privateData; } +// FindLast +/*! \brief Find the last occurrence of the given character, + starting from the given offset and going backwards. + \param c The character to search for. + \param beforeOffset The offset where to start the search. + \return The offset(zero based) into the data + where the given character has been found. +*/ int32 BString::FindLast(char c, int32 beforeOffset) const { - char tmp[2] = { c, '\0' }; + char *start = _privateData; + char *end = _privateData + Length() - beforeOffset; - return _FindBefore(tmp, beforeOffset, 1); + /* Scans the string backwards until we found the character, */ + /* or we reach the string's start */ + while(end > start && *end != c) + end--; + + if (end <= start) + return B_ERROR; + + return end - _privateData; } @@ -809,8 +1279,7 @@ BString::IFindLast(const char *string, int32 beforeOffset) const BString& BString::ReplaceFirst(char replaceThis, char withThis) { - char tmp[2] = { replaceThis, '\0' }; - int32 pos = _ShortFindAfter(tmp, 1); + int32 pos = FindFirst(replaceThis); if (pos >= 0) _privateData[pos] = withThis; @@ -822,8 +1291,7 @@ BString::ReplaceFirst(char replaceThis, char withThis) BString& BString::ReplaceLast(char replaceThis, char withThis) { - char tmp[2] = { replaceThis, '\0' }; - int32 pos = _FindBefore(tmp, Length(), 1); + int32 pos = FindLast(replaceThis); if (pos >= 0) _privateData[pos] = withThis; @@ -835,11 +1303,9 @@ BString::ReplaceLast(char replaceThis, char withThis) BString& BString::ReplaceAll(char replaceThis, char withThis, int32 fromOffset) { - int32 pos = B_ERROR; - char tmp[2] = { replaceThis, '\0' }; - - for (;;) { - pos = _FindAfter(tmp, fromOffset, 1); + for (int32 pos;;) + { + pos = FindFirst(replaceThis, fromOffset); if (pos < 0) break; _privateData[pos] = withThis; @@ -853,15 +1319,9 @@ BString::ReplaceAll(char replaceThis, char withThis, int32 fromOffset) BString& BString::Replace(char replaceThis, char withThis, int32 maxReplaceCount, int32 fromOffset) { - - char tmp[2] = { replaceThis, '\0' }; - - if (maxReplaceCount <= 0) - return *this; - - for (int32 pos ; maxReplaceCount > 0 ; maxReplaceCount--) { - - pos = _FindAfter(tmp, fromOffset, 1); + for (int32 pos ; maxReplaceCount > 0 ; maxReplaceCount--) + { + pos = FindFirst(replaceThis, fromOffset); if (pos < 0) break; @@ -882,7 +1342,8 @@ BString::ReplaceFirst(const char *replaceThis, const char *withThis) int32 firstStringLength = strlen(replaceThis); int32 pos = _ShortFindAfter(replaceThis, firstStringLength); - if (pos >= 0) { + if (pos >= 0) + { int32 len = (withThis ? strlen(withThis) : 0); int32 difference = len - firstStringLength; @@ -907,7 +1368,8 @@ BString::ReplaceLast(const char *replaceThis, const char *withThis) int32 firstStringLength = strlen(replaceThis); int32 pos = _FindBefore(replaceThis, Length(), firstStringLength); - if (pos >= 0) { + if (pos >= 0) + { int32 len = (withThis ? strlen(withThis) : 0); int32 difference = len - firstStringLength; @@ -932,15 +1394,15 @@ BString::ReplaceAll(const char *replaceThis, const char *withThis, int32 fromOff int32 firstStringLength = strlen(replaceThis); int32 len = (withThis ? strlen(withThis) : 0); int32 difference = len - firstStringLength; - - for (int32 pos;;) { - + + for (int32 pos;;) + { pos = _FindAfter(replaceThis, fromOffset, firstStringLength); if (pos < 0) break; if (difference > 0) - _OpenAtBy(pos, difference); + _OpenAtBy(pos, difference); else if (difference < 0) _ShrinkAtBy(pos, -difference); @@ -955,15 +1417,15 @@ BString::ReplaceAll(const char *replaceThis, const char *withThis, int32 fromOff BString& BString::Replace(const char *replaceThis, const char *withThis, int32 maxReplaceCount, int32 fromOffset) { - if (replaceThis == NULL || maxReplaceCount <= 0) + if (replaceThis == NULL) return *this; int32 firstStringLength = strlen(replaceThis); int32 len = (withThis ? strlen(withThis) : 0); int32 difference = len - firstStringLength; - for (int32 pos; maxReplaceCount > 0; maxReplaceCount--) { - + for (int32 pos; maxReplaceCount > 0; maxReplaceCount--) + { pos = _FindAfter(replaceThis, fromOffset, firstStringLength); if (pos < 0) break; @@ -984,7 +1446,7 @@ BString& BString::IReplaceFirst(char replaceThis, char withThis) { char tmp[2] = { replaceThis, '\0' }; - int32 pos = _FindAfter(tmp, 0, 1); + int32 pos = _IFindAfter(tmp, 0, 1); if (pos >= 0) _privateData[pos] = withThis; @@ -1011,7 +1473,8 @@ BString::IReplaceAll(char replaceThis, char withThis, int32 fromOffset) { char tmp[2] = { replaceThis, '\0' }; - for (int32 pos;;) { + for (int32 pos;;) + { pos = _IFindAfter(tmp, fromOffset, 1); if (pos < 0) break; @@ -1027,11 +1490,11 @@ BString::IReplace(char replaceThis, char withThis, int32 maxReplaceCount, int32 { char tmp[2] = { replaceThis, '\0' }; - if (_privateData == NULL || maxReplaceCount <= 0) + if (_privateData == NULL) return *this; - for (int32 pos ; maxReplaceCount > 0 ; maxReplaceCount--) { - + for (int32 pos ; maxReplaceCount > 0 ; maxReplaceCount--) + { pos = _IFindAfter(tmp, fromOffset, 1); if (pos < 0) break; @@ -1052,7 +1515,8 @@ BString::IReplaceFirst(const char *replaceThis, const char *withThis) int32 firstStringLength = strlen(replaceThis); int32 pos = _IFindAfter(replaceThis, 0, firstStringLength); - if (pos >= 0) { + if (pos >= 0) + { int32 len = (withThis ? strlen(withThis) : 0); int32 difference = len - firstStringLength; @@ -1077,7 +1541,8 @@ BString::IReplaceLast(const char *replaceThis, const char *withThis) int32 firstStringLength = strlen(replaceThis); int32 pos = _IFindBefore(replaceThis, Length(), firstStringLength); - if (pos >= 0) { + if (pos >= 0) + { int32 len = (withThis ? strlen(withThis) : 0); int32 difference = len - firstStringLength; @@ -1103,7 +1568,8 @@ BString::IReplaceAll(const char *replaceThis, const char *withThis, int32 fromOf int32 len = (withThis ? strlen(withThis) : 0); int32 difference = len - firstStringLength; - for (int32 pos;;) { + for (int32 pos;;) + { pos = _IFindAfter(replaceThis, fromOffset, firstStringLength); if (pos < 0) break; @@ -1124,15 +1590,15 @@ BString::IReplaceAll(const char *replaceThis, const char *withThis, int32 fromOf BString& BString::IReplace(const char *replaceThis, const char *withThis, int32 maxReplaceCount, int32 fromOffset) { - if (replaceThis == NULL || maxReplaceCount <= 0) + if (replaceThis == NULL) return *this; int32 firstStringLength = strlen(replaceThis); int32 len = (withThis ? strlen(withThis) : 0); int32 difference = len - firstStringLength; - for (int32 pos; maxReplaceCount > 0; maxReplaceCount--) { - + for (int32 pos; maxReplaceCount > 0; maxReplaceCount--) + { pos = _IFindAfter(replaceThis, fromOffset, firstStringLength); if (pos < 0) break; @@ -1155,17 +1621,19 @@ BString::ReplaceSet(const char *setOfChars, char with) int32 offset = 0; int32 length = Length(); - for (int32 pos;;) { + for (int32 pos;;) + { pos = strcspn(String() + offset, setOfChars); if (pos >= length) break; offset += pos; - if (offset >= Length()) + if (offset >= length) break; _privateData[offset] = with; + offset++; } return *this; @@ -1181,7 +1649,8 @@ BString::ReplaceSet(const char *setOfChars, const char *with) int32 offset = 0; int32 withLen = strlen(with); - for (int32 pos;;) { + for (int32 pos;;) + { pos = strcspn(String() + offset, setOfChars); if (pos >= Length()) break; @@ -1201,6 +1670,14 @@ BString::ReplaceSet(const char *setOfChars, const char *with) /*---- Unchecked char access -----------------------------------------------*/ + +// operator[] +/*! \brief Returns a reference to the data at the given offset. + + This function can be used to read a byte or to change its value. + \param index The index (zero based) of the byte to get. + \return Returns a reference to the specified byte. +*/ char & BString::operator[](int32 index) { @@ -1217,7 +1694,7 @@ BString::LockBuffer(int32 maxLength) int32 len = Length(); if (maxLength > len) - _privateData = _GrowBy(maxLength - len); + _GrowBy(maxLength - len); return _privateData; } @@ -1234,13 +1711,17 @@ BString::UnlockBuffer(int32 length) len = strlen(_privateData); if (len != Length()) - _privateData = _GrowBy(len - Length()); + _GrowBy(len - Length()); return *this; } /*---- Uppercase<->Lowercase ------------------------------------------------*/ +// ToLower +/*! \brief Converts the BString to lowercase + \return This function always returns *this . +*/ BString& BString::ToLower() { @@ -1252,6 +1733,10 @@ BString::ToLower() } +// ToUpper +/*! \brief Converts the BString to uppercase + \return This function always returns *this . +*/ BString& BString::ToUpper() { @@ -1263,6 +1748,10 @@ BString::ToUpper() } +// Capitalize +/*! \brief Converts the first character to uppercase, rest to lowercase + \return This function always returns *this . +*/ BString& BString::Capitalize() { @@ -1279,6 +1768,13 @@ BString::Capitalize() } +// CapitalizeEachWord +/*! \brief Converts the first character of every word to uppercase, rest to lowercase. + + Converts the first character of every "word" (series of alpabetical characters + separated by non alphabetical characters) to uppercase, and the rest to lowercase. + \return This function always returns *this . +*/ BString& BString::CapitalizeEachWord() { @@ -1289,17 +1785,21 @@ BString::CapitalizeEachWord() int32 length = Length(); do { - // Find the first alphabetical character - for(; count < length; count++) { - if (isalpha(_privateData[count])) { + // Find the first alphabetical character... + for(; count < length; count++) + { + if (isalpha(_privateData[count])) + { + // ...found! Convert it to uppercase. _privateData[count] = toupper(_privateData[count]); count++; break; } } - // Find the first non-alphabetical character, + // Now find the first non-alphabetical character, // and meanwhile, turn to lowercase all the alphabetical ones - for(; count < length; count++) { + for(; count < length; count++) + { if (isalpha(_privateData[count])) _privateData[count] = tolower(_privateData[count]); else @@ -1330,7 +1830,8 @@ BString::CharacterEscape(const char *setOfCharsToEscape, char escapeWith) int32 offset = 0; - for(int32 pos;;) { + for(int32 pos;;) + { pos = strcspn(_privateData + offset, setOfCharsToEscape); offset += pos; if (offset >= Length()) @@ -1357,12 +1858,10 @@ BString::CharacterDeescape(const char *original, char escapeChar) BString& BString::CharacterDeescape(char escapeChar) { - if (_privateData == NULL) - return *this; - - char tmp[2] = { escapeChar, '\0' }; - RemoveAll(tmp); - + int32 pos; + while ((pos = FindFirst(escapeChar)) >= 0) + _ShrinkAtBy(pos, 1); + return *this; } @@ -1372,7 +1871,7 @@ BString::CharacterDeescape(char escapeChar) BString& BString::operator<<(const char *str) { - if (str) + if (str != NULL) _DoAppend(str, strlen(str)); return *this; } @@ -1481,6 +1980,9 @@ BString::_Init(const char* str, int32 len) } +#if ENABLE_INLINES +inline +#endif void BString::_DoAssign(const char *str, int32 len) { @@ -1488,19 +1990,22 @@ BString::_DoAssign(const char *str, int32 len) int32 curLen = Length(); if (len != curLen) - _privateData = _GrowBy(len - curLen); + _GrowBy(len - curLen); memcpy(_privateData, str, len); } +#if ENABLE_INLINES +inline +#endif void BString::_DoAppend(const char *str, int32 len) { ASSERT(str != NULL); int32 length = Length(); - _privateData = _GrowBy(len); + _GrowBy(len); memcpy(_privateData + length, str, len); } @@ -1508,21 +2013,19 @@ BString::_DoAppend(const char *str, int32 len) char* BString::_GrowBy(int32 size) { - int32 curLen = Length(); - ASSERT(curLen + size >= 0); + int32 newLen = Length() + size; + ASSERT(newLen >= 0); if (_privateData != NULL) - { _privateData -= sizeof(int32); - } _privateData = (char*)realloc(_privateData, - curLen + size + sizeof(int32) + 1); + newLen + sizeof(int32) + 1); _privateData += sizeof(int32); - _SetLength(curLen + size); - _privateData[Length()] = '\0'; + _SetLength(newLen); + _privateData[newLen] = '\0'; return _privateData; } @@ -1538,7 +2041,7 @@ BString::_OpenAtBy(int32 offset, int32 length) if (_privateData != NULL) _privateData -= sizeof(int32); - _privateData = (char*)realloc(_privateData , oldLength + length + sizeof(int32) + 1); + _privateData = (char*)realloc(_privateData, oldLength + length + sizeof(int32) + 1); _privateData += sizeof(int32); memmove(_privateData + offset + length, _privateData + offset, @@ -1555,12 +2058,12 @@ char* BString::_ShrinkAtBy(int32 offset, int32 length) { int32 oldLength = Length(); - + if (offset > oldLength || offset + length > oldLength) return _privateData; memmove(_privateData + offset, _privateData + offset + length, - Length() - offset - length); + oldLength - offset - length); _privateData -= sizeof(int32); _privateData = (char*)realloc(_privateData, oldLength - length + sizeof(int32) + 1); @@ -1573,15 +2076,19 @@ BString::_ShrinkAtBy(int32 offset, int32 length) } +#if ENABLE_INLINES +inline +#endif void BString::_DoPrepend(const char *str, int32 count) { ASSERT(str != NULL); - _privateData = _OpenAtBy(0, count); + _OpenAtBy(0, count); memcpy(_privateData, str, count); } +/* XXX: These could be inlined too, if they are too slow */ int32 BString::_FindAfter(const char *str, int32 offset, int32 strlen) const { @@ -1617,15 +2124,15 @@ BString::_IFindAfter(const char *str, int32 offset, int32 strlen) const int32 -BString::_ShortFindAfter(const char *str, int32 strlen) const +BString::_ShortFindAfter(const char *str, int32 len) const { ASSERT(str != NULL); char *ptr = strstr(String(), str); - + if (ptr != NULL) return ptr - String(); - + return B_ERROR; } @@ -1637,13 +2144,14 @@ BString::_FindBefore(const char *str, int32 offset, int32 strlen) const if (offset <= 0) return B_ERROR; - - char *ptr1 = _privateData + offset - strlen; - while (ptr1 >= _privateData) { - if (!memcmp(ptr1, str, strlen)) - return ptr1 - _privateData; - ptr1--; + const char *ptr = _privateData + offset - strlen; + + while (ptr >= _privateData) + { + if (!memcmp(ptr, str, strlen)) + return ptr - _privateData; + ptr--; } return B_ERROR; @@ -1660,7 +2168,8 @@ BString::_IFindBefore(const char *str, int32 offset, int32 strlen) const char *ptr1 = _privateData + offset - strlen; - while (ptr1 >= _privateData) { + while (ptr1 >= _privateData) + { if (!strncasecmp(ptr1, str, strlen)) return ptr1 - _privateData; ptr1--; @@ -1670,6 +2179,9 @@ BString::_IFindBefore(const char *str, int32 offset, int32 strlen) const } +#if ENABLE_INLINES +inline +#endif void BString::_SetLength(int32 length) { @@ -1679,15 +2191,18 @@ BString::_SetLength(int32 length) #if DEBUG // AFAIK, these are not implemented in BeOS R5 +// XXX : Test these puppies void BString::_SetUsingAsCString(bool state) -{ +{ + //TODO: Implement ? } void BString::_AssertNotUsingAsCString() const { + //TODO: Implement ? } #endif