[interfacekit] A patch for BString
- From: Oliver Tappe <openbeos@xxxxxxxxxxxxxxx>
- To: interfacekit@xxxxxxxxxxxxx
- Date: Thu, 06 Nov 2003 11:09:30 +0100
Hi everyone,
I have finally found the time to finish the patch (which is rather large,
I'm afraid...).
Due to the comments on the list, I have decided to make as few changes to
the behaviour of BString (as compared to R5) as possible and only change
things if the behaviour of BString is a clear bug or *very* annoying.
A summary of the changes:
- memory-allocation has been centralized and BString is now capable of
handling out-of-memory situations (somewhat) gracefully: The string
is just left as is (as it was before the call).
- all length - arguments are clamped to the real length now, meaning that
BString s( "some text");
s.Remove( 4, 30);
now correctly yields " text" (not "some text" as R5 does).
- passing negative values to a fromOffset argument causes BString to return
B_ERROR if that is possible or send the app straight to the debugger.
An exception to this rule are the Insert()-methods which accept negative
values just like the R5-implemantation does (but we avoid crashing for
offsets that exceed the string-length).
- passing a insertion-position that exceeds the string-length sends the
app to the debugger.
- passing a fromOffset/beforeOffset to any search-method returns B_ERROR.
- BString's only error-code is now B_ERROR just to be compatible with the
documentation (R5 only ever returns B_ERROR, it crashes in cases where
the
openbeos implementation used to return B_BAD_VALUE).
- I have streamlined the (I)Replace... and Remove... - methods such that
BString never uses _OpenAtBy() / _ShrinkAtBy() inside a loop. This way
it avoids the pathetic performance of the R5-implementation (which is
indicated by the new tests that use large(ish) datasets).
- BString should no longer crash if given any weird offset/length arguments.
- Several tests have been added.
There is (at least >:oP ) one open problem: Since some tests will trigger a
call to the debugger if compiled with DEBUG, the unit-test will never pass.
That's a bit awkward, so I have thought about using a signal-handler in the
test-app that could be used to implement a check for a signal like this:
BString s;
CPPUNIT_ASSERT_DEBUGGER( s.Insert( "dummy", 20));
Does this kind of stuff already exist in cppunit? Is it feasible at all?
In general, it seems obvious that BString needs some more work at a later
stage. IMHO the idea of accepting negative offsets/values does make sense
and there is a need for throwing exceptions (at least bad_alloc) but I
believe this is all work that should go into R2.
As always: comments/complaints/suggestions are welcome!
cheers,
OliverIndex: headers/os/support/String.h
===================================================================
RCS file: /cvsroot/open-beos/current/headers/os/support/String.h,v
retrieving revision 1.7
diff -u -w -r1.7 String.h
--- headers/os/support/String.h 15 Feb 2003 20:08:36 -0000 1.7
+++ headers/os/support/String.h 6 Nov 2003 09:21:24 -0000
@@ -318,6 +318,14 @@
void _SetUsingAsCString(bool) {}
void _AssertNotUsingAsCString() const {}
#endif
+
+ char *_Alloc( int32);
+
+ struct PosVect;
+ void _ReplaceAtPositions( const PosVect* positions,
+
int32 searchLen,
+
const char* with,
+
int32 withLen);
protected:
char *_privateData;Index: src/kits/support/String.cpp
===================================================================
RCS file: /cvsroot/open-beos/current/src/kits/support/String.cpp,v
retrieving revision 1.32
diff -u -r1.32 String.cpp
--- src/kits/support/String.cpp 11 Feb 2003 19:16:18 -0000 1.32
+++ src/kits/support/String.cpp 6 Nov 2003 09:28:30 -0000
@@ -19,11 +19,12 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
-// File Name: String.cpp
-// Author(s): Marc Flerackers (mflerackers@xxxxxxxxxx)
-// Stefano Ceccherini (burton666@xxxxxxxxx)
+// File Name: String.cpp
+// Author(s): Marc Flerackers (mflerackers@xxxxxxxxxx)
+// Stefano Ceccherini (burton666@xxxxxxxxx)
+// Oliver Tappe (openbeos@xxxxxxxxxxxxxxx)
//
-// Description: String class supporting common string operations.
+// Description: String class supporting common string operations.
//------------------------------------------------------------------------------
// Standard Includes
-----------------------------------------------------------
@@ -46,6 +47,104 @@
#define KEEP_CASE false
#define IGNORE_CASE true
+// define proper names for count-option of _DoReplace()
+#define REPLACE_ALL 0x7FFFFFFF
+
+
+
+// helper function, returns minimum of two given values (but clamps to 0):
+static inline int32 min_clamp0( int32 num1, int32 num2)
+{
+ if (num1<num2)
+ return num1 > 0 ? num1 : 0;
+ else
+ return num2 > 0 ? num2 : 0;
+}
+
+// helper function, returns length of given string (but clamps to given
maximum):
+static inline int32 strlen_clamp( const char* str, int32 max)
+{ // this should yield 0 for max<0:
+ int32 len=0;
+ while( len<max && *str++)
+ len++;
+ return len;
+}
+
+// helper function, massages given pointer into a legal c-string:
+static inline const char* safestr( const char* str)
+{
+ return str ? str : "";
+}
+
+
+// helper class for BString::_ReplaceAtPositions():
+struct BString::PosVect {
+ PosVect()
+ : size( 0)
+ , bufSize( 20)
+ , buf( NULL)
+ {
+ }
+ ~PosVect()
+ {
+ if (buf)
+ free( buf);
+ }
+ bool Add( int32 pos)
+ {
+ if (!buf || size==bufSize) {
+ if (buf)
+ bufSize *= 2;
+ int32* newBuf = (int32*)realloc( buf,
bufSize*sizeof(int32));
+ if (!newBuf)
+ return false;
+ buf = newBuf;
+ }
+ buf[size++] = pos;
+ return true;
+ }
+ inline int32 ItemAt( int32 idx) const
+ {
+ return buf[idx];
+ }
+ inline int32 CountItems() const
+ {
+ return size;
+ }
+private:
+ int32 size;
+ int32 bufSize;
+ int32* buf;
+};
+
+
+// helper macro that is used to fall into debugger if a given param check
fails:
+#ifdef DEBUG
+ #define CHECK_PARAM( expr, msg) \
+ if (!(expr)) \
+ debugger( msg)
+
+ #define CHECK_PARAM_RET( expr, msg, retval) \
+ if (!(expr)) \
+ debugger( msg)
+
+ #define CHECK_PARAM_VOID( expr, msg) \
+ if (!(expr)) \
+ debugger( msg)
+#else
+ #define CHECK_PARAM( expr, msg) \
+ if (!(expr)) \
+ return *this
+
+ #define CHECK_PARAM_RET( expr, msg, retval) \
+ if (!(expr)) \
+ return (retval);
+
+ #define CHECK_PARAM_VOID( expr, msg)
+#endif
+
+//
-----------------------------------------------------------------------------
+
/*!
\class BString
\brief String class supporting common string operations
@@ -56,6 +155,7 @@
\author <a href='mailto:mflerackers@xxxxxxxxxx>Marc Flerackers</a>
\author <a href='mailto:burton666@xxxxxxxxxxx>Stefano Ceccherini</a>
+ \author <a href='mailto:openbeos@xxxxxxxxxxxxxx>Oliver Tappe</a>
*/
/*! \var char* BString::_privateData
@@ -105,8 +205,8 @@
{
if (str != NULL)
{
- int32 len = (int32)strlen(str);
- _Init(str, min_c(len, maxLength));
+ int32 len = strlen_clamp( str, maxLength);
+ _Init(str, len);
}
}
@@ -177,10 +277,9 @@
count++;
// Jump to next UTF8 character
- for (; (*start & 0xc0) == 0x80; start++);
+ for (; (*start & 0xc0) == 0x80; start++);
}
-
return count;
}
@@ -228,12 +327,7 @@
BString&
BString::operator=(char c)
{
- int32 curLen = Length();
-
- if (curLen != 1)
- _GrowBy(1 - curLen);
- _privateData[0] = c;
-
+ _DoAssign(&c, 1);
return *this;
}
@@ -250,8 +344,8 @@
{
if (str != NULL)
{
- int32 len = (int32)strlen(str);
- _DoAssign(str, min_c(length, len));
+ int32 len = strlen_clamp( str, length);
+ _DoAssign(str, len);
}
else
_GrowBy(-Length()); // Empties the string
@@ -309,7 +403,7 @@
BString::SetTo(const BString &string, int32 length)
{
if (&string != this) // Avoid auto-assignment
- _DoAssign(string.String(), min_c(length, string.Length()));
+ _DoAssign(string.String(), min_clamp0(length, string.Length()));
return *this;
}
@@ -326,16 +420,18 @@
{
if (&from == this) // Avoid auto-adoption
return *this;
-
+
+ int32 len = min_clamp0(length, from.Length());
+
if (_privateData)
free(_privateData - sizeof(int32));
/* "steal" the data from the given BString */
_privateData = from._privateData;
from._privateData = NULL;
-
- if (length < Length())
- _privateData = _GrowBy(length - Length()); //Negative
+
+ if (len < Length())
+ _GrowBy(len - Length()); // Negative, we truncate
return *this;
}
@@ -351,13 +447,12 @@
BString&
BString::SetTo(char c, int32 count)
{
+ if (count<0)
+ count = 0;
int32 curLen = Length();
- if (curLen != count)
- _GrowBy(count - curLen);
-
- memset(_privateData, c, count);
-
+ if (curLen == count || _GrowBy(count - curLen))
+ memset(_privateData, c, count);
return *this;
}
@@ -374,8 +469,13 @@
BString &
BString::CopyInto(BString &into, int32 fromOffset, int32 length) const
{
- if (&into != this)
- into.SetTo(String() + fromOffset, length);
+ if (&into != this) {
+ CHECK_PARAM_RET( fromOffset>=0, "'fromOffset' must not be
negative!",
+ into);
+ CHECK_PARAM_RET( fromOffset<=Length(), "'fromOffset' exceeds
length!",
+ into);
+ into.SetTo( String() + fromOffset, length);
+ }
return into;
}
@@ -391,8 +491,9 @@
{
if (into != NULL)
{
- int32 len = Length() - fromOffset;
- len = min_c(len, length);
+ CHECK_PARAM_VOID( fromOffset>=0, "'fromOffset' must not be
negative!");
+ CHECK_PARAM_VOID( fromOffset<=Length(), "'fromOffset' exceeds
length!");
+ int32 len = min_clamp0( length, Length() - fromOffset);
memcpy(into, _privateData + fromOffset, len);
}
}
@@ -421,9 +522,7 @@
BString&
BString::operator+=(char c)
{
- _GrowBy(1);
- _privateData[Length() - 1] = c;
-
+ _DoAppend(&c, 1);
return *this;
}
@@ -437,7 +536,7 @@
BString&
BString::Append(const BString &string, int32 length)
{
- _DoAppend(string.String(), min_c(length, string.Length()));
+ _DoAppend(string.String(), min_clamp0(length, string.Length()));
return *this;
}
@@ -453,8 +552,8 @@
{
if (str != NULL)
{
- int32 len = (int32)strlen(str);
- _DoAppend(str, min_c(len, length));
+ int32 len = strlen_clamp( str, length);
+ _DoAppend(str, len);
}
return *this;
}
@@ -470,8 +569,8 @@
BString::Append(char c, int32 count)
{
int32 len = Length();
- _GrowBy(count);
- memset(_privateData + len, c, count);
+ if (count>0 && _GrowBy(count))
+ memset(_privateData + len, c, count);
return *this;
}
@@ -517,8 +616,8 @@
{
if (str != NULL)
{
- int32 len = (int32)strlen(str);
- _DoPrepend(str, min_c(len, length));
+ int32 len = strlen_clamp( str, length);
+ _DoPrepend(str, len);
}
return *this;
}
@@ -534,7 +633,7 @@
BString::Prepend(const BString &string, int32 len)
{
if (&string != this)
- _DoPrepend(string.String(), min_c(len, string.Length()));
+ _DoPrepend(string.String(), min_clamp0(len, string.Length()));
return *this;
}
@@ -548,8 +647,8 @@
BString&
BString::Prepend(char c, int32 count)
{
- _OpenAtBy(0, count);
- memset(_privateData, c, count);
+ if (count>0 && _OpenAtBy(0, count))
+ memset(_privateData, c, count);
return *this;
}
@@ -567,13 +666,18 @@
{
if (str != NULL)
{
+ CHECK_PARAM( pos<=Length(), "'pos' exceeds length!");
+ int32 len = (int32)strlen(str);
if (pos < 0)
{
- str -= pos;
+ int32 skipLen = min_clamp0( -1*pos, len);
+ str += skipLen;
+ len -= skipLen;
pos = 0;
- }
- _privateData = _OpenAtBy(pos, strlen(str));
- memcpy(_privateData + pos, str, strlen(str));
+ } else
+ pos = min_clamp0( pos, Length());
+ if (_OpenAtBy(pos, len))
+ memcpy(_privateData + pos, str, len);
}
return *this;
}
@@ -591,15 +695,18 @@
{
if (str != NULL)
{
- if (pos < 0)
+ CHECK_PARAM( pos<=Length(), "'pos' exceeds length!");
+ int32 len = strlen_clamp(str, length);
+ if (pos < 0)
{
- str -= pos;
+ int32 skipLen = min_clamp0( -1*pos, len);
+ str += skipLen;
+ len -= skipLen;
pos = 0;
- }
- int32 len = (int32)strlen(str);
- len = min_c(len, length);
- _OpenAtBy(pos, len);
- memcpy(_privateData + pos, str, len);
+ } else
+ pos = min_clamp0( pos, Length());
+ if (_OpenAtBy(pos, len))
+ memcpy(_privateData + pos, str, len);
}
return *this;
}
@@ -616,14 +723,8 @@
BString&
BString::Insert(const char *str, int32 fromOffset, int32 length, int32 pos)
{
- if (str != NULL)
- {
- int32 len = (int32)strlen(str);
- len = min_c(len - fromOffset, length);
- _privateData = _OpenAtBy(pos, len);
- memcpy(_privateData + pos, str + fromOffset, len);
- }
- return *this;
+ CHECK_PARAM( fromOffset>=0, "'fromOffset' must not be negative!");
+ return Insert( str+fromOffset, length, pos);
}
@@ -669,8 +770,10 @@
BString&
BString::Insert(const BString &string, int32 fromOffset, int32 length, int32
pos)
{
- if (&string != this)
- Insert(string.String(), fromOffset, length, pos); //TODO:
Optimize
+ if (&string != this) {
+ CHECK_PARAM( fromOffset>=0, "'fromOffset' must not be
negative!");
+ Insert( string.String()+fromOffset, length, pos);
+ }
return *this;
}
@@ -685,9 +788,15 @@
BString&
BString::Insert(char c, int32 count, int32 pos)
{
- _OpenAtBy(pos, count);
- memset(_privateData + pos, c, count);
-
+ CHECK_PARAM( pos<=Length(), "'pos' exceeds length!");
+ if (pos < 0)
+ {
+ count = max_c( count + pos, 0);
+ pos = 0;
+ } else
+ pos = min_clamp0( pos, Length());
+ if (count > 0 && _OpenAtBy(pos, count))
+ memset(_privateData + pos, c, count);
return *this;
}
@@ -696,7 +805,7 @@
// Truncate
/*! \brief Truncate the string to the new length.
\param newLength The new lenght of the string.
- \param lazy Currently unused. (?)
+ \param lazy If true, the memory-optimisation is postponed to later
\return This function always returns *this .
*/
BString&
@@ -707,13 +816,13 @@
int32 curLen = Length();
- if (newLength < curLen)
- {
-
- //TODO: Implement lazy truncate?
-
- _GrowBy(newLength - curLen); //Negative
- _privateData[newLength] = '\0';
+ if (newLength < curLen) {
+ if (lazy) {
+ // don't free memory yet, just set new length:
+ _SetLength( newLength);
+ _privateData[newLength] = '\0';
+ } else
+ _GrowBy(newLength - curLen); //Negative
}
return *this;
}
@@ -728,7 +837,15 @@
BString&
BString::Remove(int32 from, int32 length)
{
- _ShrinkAtBy(from, length);
+ int32 len = Length();
+ if (from < 0)
+ {
+ int32 skipLen = min_clamp0( from, len);
+ len -= skipLen;
+ from = 0;
+ } else
+ from = min_clamp0( from, len);
+ _ShrinkAtBy( from, min_clamp0(length, len-from));
return *this;
}
@@ -775,7 +892,7 @@
BString&
BString::RemoveAll(const BString &string)
{
- return _DoReplace( string.String(), "", 0x7FFFFFFF, 0, KEEP_CASE);
+ return _DoReplace( string.String(), "", REPLACE_ALL, 0, KEEP_CASE);
}
@@ -824,7 +941,7 @@
BString&
BString::RemoveAll(const char *str)
{
- return _DoReplace( str, "", 0x7FFFFFFF, 0, KEEP_CASE);
+ return _DoReplace( str, "", REPLACE_ALL, 0, KEEP_CASE);
}
@@ -836,26 +953,7 @@
BString&
BString::RemoveSet(const char *setOfCharsToRemove)
{
- char* buf;
- if (setOfCharsToRemove && (buf=LockBuffer( Length())) != NULL) {
- char* oldPos = buf;
- char* newPos = buf;
- int32 len;
- int32 lenToGo = Length();
- while( (len = strcspn( oldPos, setOfCharsToRemove)) < lenToGo) {
- if (oldPos>newPos)
- memmove( newPos, oldPos, len);
- newPos += len++;
- oldPos += len;
- lenToGo -= len;
- }
- if (oldPos>newPos)
- memmove( newPos, oldPos, lenToGo);
- newPos += lenToGo;
- *newPos = 0;
- UnlockBuffer( newPos-buf);
- }
- return *this;
+ return ReplaceSet( setOfCharsToRemove, "");
}
@@ -864,24 +962,27 @@
\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 .
+ \return This function always returns into.
*/
BString&
BString::MoveInto(BString &into, int32 from, int32 length)
{
- if (&into == this)
+ CHECK_PARAM_RET( from>=0, "'from' must not be negative!", into);
+ CHECK_PARAM_RET( from<=Length(), "'from' exceeds length!", into);
+ int32 len = min_clamp0( length, Length() - from);
+ if (&into == this) {
+ /* [zooey]: to be activated later (>R1):
+ // strings are identical, just move the data:
+ if (from>0 && _privateData)
+ memmove( _privateData, _privateData+from, len);
+ Truncate( len);
+ */
return *this;
-
- int32 len = Length() - from;
-
- len = min_c(len, length);
-
- into.SetTo(String() + from, length);
-
- if (from + length <= Length())
- _privateData = _ShrinkAtBy(from, len);
+ }
+ into.SetTo(String() + from, len);
+ _ShrinkAtBy(from, len);
- return *this;
+ return into;
}
@@ -896,11 +997,13 @@
{
if (into != NULL)
{
- memcpy(into, String() + from, length);
- if (from + length <= Length())
- _privateData = _ShrinkAtBy(from, length);
- into[length] = '\0';
- }
+ CHECK_PARAM_VOID( from>=0, "'from' must not be negative!");
+ CHECK_PARAM_VOID( from<=Length(), "'from' exceeds length!");
+ int32 len = min_clamp0(length, Length() - from);
+ memcpy(into, String() + from, len);
+ into[len] = '\0';
+ _ShrinkAtBy(from, len);
+ }
}
@@ -908,35 +1011,35 @@
bool
BString::operator<(const char *string) const
{
- return strcmp(String(), string) < 0;
+ return strcmp(String(), safestr(string)) < 0;
}
bool
BString::operator<=(const char *string) const
{
- return strcmp(String(), string) <= 0;
+ return strcmp(String(), safestr(string)) <= 0;
}
bool
BString::operator==(const char *string) const
{
- return strcmp(String(), string) == 0;
+ return strcmp(String(), safestr(string)) == 0;
}
bool
BString::operator>=(const char *string) const
{
- return strcmp(String(), string) >= 0;
+ return strcmp(String(), safestr(string)) >= 0;
}
bool
BString::operator>(const char *string) const
{
- return strcmp(String(), string) > 0;
+ return strcmp(String(), safestr(string)) > 0;
}
@@ -951,7 +1054,7 @@
int
BString::Compare(const char *string) const
{
- return strcmp(String(), string);
+ return strcmp(String(), safestr(string));
}
@@ -965,7 +1068,7 @@
int
BString::Compare(const char *string, int32 n) const
{
- return strncmp(String(), string, n);
+ return strncmp(String(), safestr(string), n);
}
@@ -979,7 +1082,7 @@
int
BString::ICompare(const char *str) const
{
- return strcasecmp(String(), str);
+ return strcasecmp(String(), safestr(str));
}
@@ -993,7 +1096,7 @@
int
BString::ICompare(const char *str, int32 n) const
{
- return strncasecmp(String(), str, n);
+ return strncasecmp(String(), safestr(str), n);
}
@@ -1021,7 +1124,7 @@
BString::FindFirst(const char *string) const
{
if (string == NULL)
- return B_BAD_VALUE;
+ return B_ERROR;
return _ShortFindAfter(string, strlen(string));
}
@@ -1037,7 +1140,10 @@
int32
BString::FindFirst(const BString &string, int32 fromOffset) const
{
- return _FindAfter(string.String(), fromOffset, string.Length());
+ if (fromOffset<0)
+ return B_ERROR;
+ return _FindAfter( string.String(), min_clamp0(fromOffset, Length()),
+ string.Length());
}
@@ -1052,9 +1158,9 @@
int32
BString::FindFirst(const char *string, int32 fromOffset) const
{
- if (string == NULL)
- return B_BAD_VALUE;
- return _FindAfter(string, fromOffset, strlen(string));
+ if (string == NULL || fromOffset<0)
+ return B_ERROR;
+ return _FindAfter(string, min_clamp0(fromOffset, Length()),
strlen(string));
}
@@ -1067,10 +1173,10 @@
int32
BString::FindFirst(char c) const
{
- char *start = _privateData;
- char *end = _privateData + Length(); /* String's end */
+ const char *start = String();
+ const char *end = String() + Length(); /* String's end */
- /* Scans the string until we found the character, */
+ /* Scans the string until we find the character, */
/* or we hit the string's end */
while(start != end && *start != c)
start++;
@@ -1078,7 +1184,7 @@
if (start == end)
return B_ERROR;
- return start - _privateData;
+ return start - String();
}
@@ -1093,8 +1199,10 @@
int32
BString::FindFirst(char c, int32 fromOffset) const
{
- char *start = _privateData + fromOffset;
- char *end = _privateData + Length(); /* String's end */
+ if (fromOffset<0)
+ return B_ERROR;
+ const char *start = String() + min_clamp0( fromOffset, Length());
+ const char *end = String() + Length(); /* String's end */
/* Scans the string until we found the character, */
/* or we hit the string's end */
@@ -1104,7 +1212,7 @@
if (start >= end)
return B_ERROR;
- return start - _privateData;
+ return start - String();
}
@@ -1131,7 +1239,7 @@
BString::FindLast(const char *string) const
{
if (string == NULL)
- return B_BAD_VALUE;
+ return B_ERROR;
return _FindBefore(string, Length(), strlen(string));
}
@@ -1147,7 +1255,10 @@
int32
BString::FindLast(const BString &string, int32 beforeOffset) const
{
- return _FindBefore(string.String(), beforeOffset, string.Length());
+ if (beforeOffset<0)
+ return B_ERROR;
+ return _FindBefore(string.String(), min_clamp0(beforeOffset,Length()),
+ string.Length());
}
@@ -1161,9 +1272,9 @@
int32
BString::FindLast(const char *string, int32 beforeOffset) const
{
- if (string == NULL)
- return B_BAD_VALUE;
- return _FindBefore(string, beforeOffset, strlen(string));
+ if (string == NULL || beforeOffset<0)
+ return B_ERROR;
+ return _FindBefore(string, min_clamp0(beforeOffset,Length()),
strlen(string));
}
@@ -1176,8 +1287,8 @@
int32
BString::FindLast(char c) const
{
- char *start = _privateData;
- char *end = _privateData + Length(); /* String's end */
+ const char *start = String();
+ const char *end = String() + Length(); /* String's end */
/* Scans the string backwards until we found the character, */
/* or we reach the string's start */
@@ -1187,7 +1298,7 @@
if (end == start)
return B_ERROR;
- return end - _privateData;
+ return end - String();
}
@@ -1202,8 +1313,10 @@
int32
BString::FindLast(char c, int32 beforeOffset) const
{
- char *start = _privateData;
- char *end = _privateData + Length() - beforeOffset;
+ if (beforeOffset < 0)
+ return B_ERROR;
+ const char *start = String();
+ const char *end = String() + Length() - beforeOffset;
/* Scans the string backwards until we found the character, */
/* or we reach the string's start */
@@ -1213,7 +1326,7 @@
if (end <= start)
return B_ERROR;
- return end - _privateData;
+ return end - String();
}
@@ -1228,7 +1341,7 @@
BString::IFindFirst(const char *string) const
{
if (string == NULL)
- return B_BAD_VALUE;
+ return B_ERROR;
return _IFindAfter(string, 0, strlen(string));
}
@@ -1236,16 +1349,19 @@
int32
BString::IFindFirst(const BString &string, int32 fromOffset) const
{
- return _IFindAfter(string.String(), fromOffset, string.Length());
+ if (fromOffset < 0)
+ return B_ERROR;
+ return _IFindAfter(string.String(), min_clamp0(fromOffset,Length()),
+ string.Length());
}
int32
BString::IFindFirst(const char *string, int32 fromOffset) const
{
- if (string == NULL)
- return B_BAD_VALUE;
- return _IFindAfter(string, fromOffset, strlen(string));
+ if (string == NULL || fromOffset < 0)
+ return B_ERROR;
+ return _IFindAfter(string, min_clamp0(fromOffset,Length()),
strlen(string));
}
@@ -1260,7 +1376,7 @@
BString::IFindLast(const char *string) const
{
if (string == NULL)
- return B_BAD_VALUE;
+ return B_ERROR;
return _IFindBefore(string, Length(), strlen(string));
}
@@ -1268,16 +1384,20 @@
int32
BString::IFindLast(const BString &string, int32 beforeOffset) const
{
- return _IFindBefore(string.String(), beforeOffset, string.Length());
+ if (beforeOffset < 0)
+ return B_ERROR;
+ return _IFindBefore(string.String(), min_clamp0(beforeOffset,Length()),
+ string.Length());
}
int32
BString::IFindLast(const char *string, int32 beforeOffset) const
{
- if (string == NULL)
- return B_BAD_VALUE;
- return _IFindBefore(string, beforeOffset, strlen(string));
+ if (string == NULL || beforeOffset < 0)
+ return B_ERROR;
+ return _IFindBefore(string, min_clamp0(beforeOffset,Length()),
+ strlen(string));
}
@@ -1309,13 +1429,13 @@
BString&
BString::ReplaceAll(char replaceThis, char withThis, int32 fromOffset)
{
- for (int32 pos;;)
+ CHECK_PARAM( fromOffset>=0, "'fromOffset' must not be negative!");
+ for (int32 pos = min_clamp0(fromOffset,Length());;)
{
- pos = FindFirst(replaceThis, fromOffset);
+ pos = FindFirst(replaceThis, pos);
if (pos < 0)
break;
_privateData[pos] = withThis;
- fromOffset = pos;
}
return *this;
@@ -1325,15 +1445,17 @@
BString&
BString::Replace(char replaceThis, char withThis, int32 maxReplaceCount, int32
fromOffset)
{
- for (int32 pos ; maxReplaceCount > 0 ; maxReplaceCount--)
+ CHECK_PARAM( fromOffset>=0, "'fromOffset' must not be negative!");
+ if (maxReplaceCount > 0)
{
- pos = FindFirst(replaceThis, fromOffset);
- if (pos < 0)
- break;
-
- _privateData[pos] = withThis;
- fromOffset = pos;
-
+ for (int32 pos=min_clamp0(fromOffset,Length());
+ maxReplaceCount > 0; maxReplaceCount--)
+ {
+ pos = FindFirst(replaceThis, pos);
+ if (pos < 0)
+ break;
+ _privateData[pos] = withThis;
+ }
}
return *this;
}
@@ -1360,11 +1482,16 @@
int32 len = (withThis ? strlen(withThis) : 0);
int32 difference = len - firstStringLength;
- if (difference > 0)
- _OpenAtBy(pos, difference);
+ if (difference > 0)
+ {
+ if (!_OpenAtBy(pos, difference))
+ return *this;
+ }
else if (difference < 0)
- _ShrinkAtBy(pos, -difference);
-
+ {
+ if (!_ShrinkAtBy(pos, -difference))
+ return *this;
+ }
memcpy(_privateData + pos, withThis, len);
}
@@ -1375,14 +1502,18 @@
BString&
BString::ReplaceAll(const char *replaceThis, const char *withThis, int32
fromOffset)
{
- return _DoReplace( replaceThis, withThis, 0x7FFFFFFF, fromOffset,
KEEP_CASE);
+ CHECK_PARAM( fromOffset>=0, "'fromOffset' must not be negative!");
+ return _DoReplace( replaceThis, withThis, REPLACE_ALL,
+
min_clamp0(fromOffset,Length()), KEEP_CASE);
}
BString&
BString::Replace(const char *replaceThis, const char *withThis, int32
maxReplaceCount, int32 fromOffset)
{
- return _DoReplace( replaceThis, withThis, maxReplaceCount, fromOffset,
KEEP_CASE);
+ CHECK_PARAM( fromOffset>=0, "'fromOffset' must not be negative!");
+ return _DoReplace( replaceThis, withThis, maxReplaceCount,
+
min_clamp0(fromOffset,Length()), KEEP_CASE);
}
@@ -1415,15 +1546,16 @@
BString&
BString::IReplaceAll(char replaceThis, char withThis, int32 fromOffset)
{
+ CHECK_PARAM( fromOffset>=0, "'fromOffset' must not be negative!");
+
char tmp[2] = { replaceThis, '\0' };
-
- for (int32 pos;;)
+
+ for (int32 pos=min_clamp0(fromOffset,Length());;)
{
- pos = _IFindAfter(tmp, fromOffset, 1);
+ pos = _IFindAfter(tmp, pos, 1);
if (pos < 0)
break;
_privateData[pos] = withThis;
- fromOffset = pos;
}
return *this;
}
@@ -1432,19 +1564,20 @@
BString&
BString::IReplace(char replaceThis, char withThis, int32 maxReplaceCount,
int32 fromOffset)
{
+ CHECK_PARAM( fromOffset>=0, "'fromOffset' must not be negative!");
+
char tmp[2] = { replaceThis, '\0' };
if (_privateData == NULL)
return *this;
- for (int32 pos ; maxReplaceCount > 0 ; maxReplaceCount--)
+ for (int32 pos=min_clamp0(fromOffset,Length());
+ maxReplaceCount > 0; maxReplaceCount--)
{
- pos = _IFindAfter(tmp, fromOffset, 1);
+ pos = _IFindAfter(tmp, pos, 1);
if (pos < 0)
break;
-
_privateData[pos] = withThis;
- fromOffset = pos;
}
return *this;
}
@@ -1472,11 +1605,17 @@
int32 difference = len - firstStringLength;
if (difference > 0)
- _OpenAtBy(pos, difference);
+ {
+ if (!_OpenAtBy(pos, difference))
+ return *this;
+ }
else if (difference < 0)
- _ShrinkAtBy(pos, -difference);
-
+ {
+ if (!_ShrinkAtBy(pos, -difference))
+ return *this;
+ }
memcpy(_privateData + pos, withThis, len);
+
}
return *this;
@@ -1486,31 +1625,35 @@
BString&
BString::IReplaceAll(const char *replaceThis, const char *withThis, int32
fromOffset)
{
- return _DoReplace( replaceThis, withThis, 0x7FFFFFFF, fromOffset,
IGNORE_CASE);
+ CHECK_PARAM( fromOffset>=0, "'fromOffset' must not be negative!");
+ return _DoReplace( replaceThis, withThis, REPLACE_ALL,
+
min_clamp0(fromOffset,Length()), IGNORE_CASE);
}
BString&
BString::IReplace(const char *replaceThis, const char *withThis, int32
maxReplaceCount, int32 fromOffset)
{
- return _DoReplace( replaceThis, withThis, maxReplaceCount, fromOffset,
IGNORE_CASE);
+ CHECK_PARAM( fromOffset>=0, "'fromOffset' must not be negative!");
+ return _DoReplace( replaceThis, withThis, maxReplaceCount,
+
min_clamp0(fromOffset,Length()), IGNORE_CASE);
}
BString&
BString::ReplaceSet(const char *setOfChars, char with)
{
+ if (setOfChars == NULL)
+ return *this;
+
int32 offset = 0;
int32 length = Length();
for (int32 pos;;)
{
pos = strcspn(String() + offset, setOfChars);
- if (pos >= length)
- break;
-
+
offset += pos;
-
if (offset >= length)
break;
@@ -1521,32 +1664,32 @@
return *this;
}
-
BString&
BString::ReplaceSet(const char *setOfChars, const char *with)
{
- if (with == NULL)
- return *this; //TODO: do something smart
-
- int32 offset = 0;
- int32 withLen = strlen(with);
+ int32 withLen = with ? strlen(with) : 0;
+ if (withLen == 1)
+ // delegate simple case:
+ return ReplaceSet( setOfChars, *with);
+
+ if (setOfChars == NULL || _privateData == NULL)
+ return *this;
- for (int32 pos;;)
+ PosVect positions;
+
+ int32 searchLen = 1;
+ int32 len = Length();
+ int32 pos = 0;
+ for (int32 offset = 0; offset < len; offset += (pos+searchLen))
{
- pos = strcspn(String() + offset, setOfChars);
- if (pos >= Length())
+ pos = strcspn(_privateData + offset, setOfChars);
+ if (pos+offset>=len)
break;
-
- offset += pos;
-
- if (offset >= Length())
- break;
-
- _OpenAtBy(offset, withLen - 1);
- memcpy(_privateData + offset, with, withLen);
- offset += withLen;
+ if (!positions.Add( offset+pos))
+ return *this;
}
-
+
+ _ReplaceAtPositions( &positions, searchLen, with, withLen);
return *this;
}
@@ -1576,7 +1719,18 @@
int32 len = Length();
if (maxLength > len)
- _GrowBy(maxLength - len);
+ {
+ if (!_GrowBy(maxLength - len))
+ return NULL;
+ if (!len && _privateData)
+ // if string was empty before call to LockBuffer(), we
make sure the
+ // buffer represents an empty c-string:
+ *_privateData = '\0';
+ }
+ else if (!maxLength && !len)
+ { // special case for unallocated string, we return an empty
c-string:
+ return const_cast<char*>( String());
+ }
return _privateData;
}
@@ -1710,19 +1864,51 @@
if (setOfCharsToEscape == NULL || _privateData == NULL)
return *this;
- int32 offset = 0;
-
- for(int32 pos;;)
+ PosVect positions;
+ int32 len = Length();
+ int32 pos = 0;
+ for (int32 offset = 0; offset < len; offset += pos+1)
{
- pos = strcspn(_privateData + offset, setOfCharsToEscape);
- offset += pos;
- if (offset >= Length())
- break;
- _OpenAtBy(offset, 1);
- memset(_privateData + offset, escapeWith, 1);
- offset += 2;
+ if ((pos = strcspn(_privateData + offset, setOfCharsToEscape))
< len-offset)
+ if (!positions.Add( offset+pos))
+ return *this;
}
-
+
+ uint32 count = positions.CountItems();
+ int32 newLength = len + count;
+ if (!newLength) {
+ _GrowBy( -len);
+ return *this;
+ }
+ int32 lastPos = 0;
+ char* oldAdr = _privateData;
+ char* newData = (char*)malloc( newLength+sizeof(int32)+1);
+ if (newData) {
+ newData += sizeof(int32);
+ char* newAdr = newData;
+ for( uint32 i=0; i<count; ++i)
+ {
+ pos = positions.ItemAt( i);
+ len = pos-lastPos;
+ if (len>0) {
+ memcpy(newAdr, oldAdr, len);
+ oldAdr += len;
+ newAdr += len;
+ }
+ *newAdr++ = escapeWith;
+ *newAdr++ = *oldAdr++;
+ lastPos = pos+1;
+ }
+ len = Length()+1-lastPos;
+ if (len>0) {
+ memcpy(newAdr, oldAdr, len);
+ }
+ free( _privateData-sizeof(int32));
+ _privateData = newData;
+ _privateData[newLength] = 0;
+ _SetLength( newLength);
+ }
+
return *this;
}
@@ -1740,11 +1926,8 @@
BString&
BString::CharacterDeescape(char escapeChar)
{
- int32 pos;
- while ((pos = FindFirst(escapeChar)) >= 0)
- _ShrinkAtBy(pos, 1);
-
- return *this;
+ const char temp[2] = {escapeChar, 0};
+ return _DoReplace( temp, "", REPLACE_ALL, 0, KEEP_CASE);
}
@@ -1846,19 +2029,35 @@
/*---- Private or Reserved ------------------------------------------------*/
+char*
+BString::_Alloc( int32 dataLen)
+{
+ char* dataPtr = _privateData ? _privateData-sizeof(int32) : NULL;
+ if (dataLen<=0)
+ { // release buffer if requested size is 0:
+ if (dataPtr)
+ free( dataPtr);
+ _privateData = NULL;
+ return NULL;
+ }
+ int32 allocLen = dataLen + sizeof(int32) + 1;
+ dataPtr = (char*)realloc( dataPtr, allocLen);
+ if (dataPtr)
+ {
+ dataPtr += sizeof(int32);
+ _privateData = dataPtr;
+ int32 newLen = allocLen - sizeof(int32) - 1;
+ _SetLength( newLen);
+ _privateData[newLen] = '\0';
+ }
+ return dataPtr;
+}
+
void
BString::_Init(const char* str, int32 len)
{
- ASSERT(str != NULL);
- ASSERT(_privateData == NULL);
-
- _privateData = (char*)malloc(len + sizeof(int32) + 1);
- _privateData += sizeof(int32);
-
- memcpy(_privateData, str, len);
-
- _SetLength(len);
- _privateData[len] = '\0';
+ if (_Alloc( len))
+ memcpy(_privateData, str, len);
}
@@ -1868,13 +2067,10 @@
void
BString::_DoAssign(const char *str, int32 len)
{
- ASSERT(str != NULL);
int32 curLen = Length();
- if (len != curLen)
- _GrowBy(len - curLen);
-
- memcpy(_privateData, str, len);
+ if (len == curLen || _GrowBy(len - curLen))
+ memcpy(_privateData, str, len);
}
@@ -1884,11 +2080,9 @@
void
BString::_DoAppend(const char *str, int32 len)
{
- ASSERT(str != NULL);
-
int32 length = Length();
- _GrowBy(len);
- memcpy(_privateData + length, str, len);
+ if (_GrowBy(len))
+ memcpy(_privateData + length, str, len);
}
@@ -1896,65 +2090,36 @@
BString::_GrowBy(int32 size)
{
int32 newLen = Length() + size;
- ASSERT(newLen >= 0);
-
- if (_privateData != NULL)
- _privateData -= sizeof(int32);
-
- _privateData = (char*)realloc(_privateData,
- newLen + sizeof(int32) + 1);
-
- _privateData += sizeof(int32);
-
- _SetLength(newLen);
- _privateData[newLen] = '\0';
-
- return _privateData;
+ return _Alloc( newLen);
}
char *
BString::_OpenAtBy(int32 offset, int32 length)
{
- ASSERT(offset >= 0);
-
int32 oldLength = Length();
- if (_privateData != NULL)
- _privateData -= sizeof(int32);
+ char* newData = _Alloc( oldLength + length);
+ if (newData != NULL)
+ memmove(_privateData + offset + length, _privateData + offset,
+ oldLength - offset);
- _privateData = (char*)realloc(_privateData, oldLength + length +
sizeof(int32) + 1);
- _privateData += sizeof(int32);
-
- memmove(_privateData + offset + length, _privateData + offset,
- oldLength - offset);
-
- _SetLength(oldLength + length);
- _privateData[Length()] = '\0';
-
- return _privateData;
+ return newData;
}
char*
BString::_ShrinkAtBy(int32 offset, int32 length)
{
+ if (!_privateData)
+ return NULL;
int32 oldLength = Length();
-
- if (offset > oldLength || offset + length > oldLength)
- return _privateData;
memmove(_privateData + offset, _privateData + offset + length,
- oldLength - offset - length);
-
- _privateData -= sizeof(int32);
- _privateData = (char*)realloc(_privateData, oldLength - length +
sizeof(int32) + 1);
- _privateData += sizeof(int32);
-
- _SetLength(oldLength - length);
- _privateData[Length()] = '\0';
-
- return _privateData;
+ oldLength - offset - length);
+
+ // the following actually should never fail, since we are reducing the
size...
+ return _Alloc( oldLength - length);
}
@@ -1964,9 +2129,8 @@
void
BString::_DoPrepend(const char *str, int32 count)
{
- ASSERT(str != NULL);
- _OpenAtBy(0, count);
- memcpy(_privateData, str, count);
+ if (_OpenAtBy(0, count))
+ memcpy(_privateData, str, count);
}
@@ -1974,11 +2138,6 @@
int32
BString::_FindAfter(const char *str, int32 offset, int32 strlen) const
{
- ASSERT(str != NULL);
-
- if (offset > Length())
- return B_ERROR;
-
char *ptr = strstr(String() + offset, str);
if (ptr != NULL)
@@ -1991,11 +2150,6 @@
int32
BString::_IFindAfter(const char *str, int32 offset, int32 strlen) const
{
- ASSERT(str != NULL);
-
- if (offset > Length())
- return B_ERROR;
-
char *ptr = strcasestr(String() + offset, str);
if (ptr != NULL)
@@ -2008,8 +2162,6 @@
int32
BString::_ShortFindAfter(const char *str, int32 len) const
{
- ASSERT(str != NULL);
-
char *ptr = strstr(String(), str);
if (ptr != NULL)
@@ -2022,20 +2174,17 @@
int32
BString::_FindBefore(const char *str, int32 offset, int32 strlen) const
{
- ASSERT(str != NULL);
-
- if (offset <= 0)
- return B_ERROR;
-
- const char *ptr = _privateData + offset - strlen;
-
- while (ptr >= _privateData)
- {
- if (!memcmp(ptr, str, strlen))
- return ptr - _privateData;
- ptr--;
+ if (_privateData)
+ {
+ const char *ptr = _privateData + offset - strlen;
+
+ while (ptr >= _privateData)
+ {
+ if (!memcmp(ptr, str, strlen))
+ return ptr - _privateData;
+ ptr--;
+ }
}
-
return B_ERROR;
}
@@ -2043,56 +2192,20 @@
int32
BString::_IFindBefore(const char *str, int32 offset, int32 strlen) const
{
- ASSERT(str != NULL);
-
- if (offset <= 0)
- return B_ERROR;
-
- char *ptr1 = _privateData + offset - strlen;
-
- while (ptr1 >= _privateData)
+ if (_privateData)
{
- if (!strncasecmp(ptr1, str, strlen))
- return ptr1 - _privateData;
- ptr1--;
+ char *ptr1 = _privateData + offset - strlen;
+
+ while (ptr1 >= _privateData)
+ {
+ if (!strncasecmp(ptr1, str, strlen))
+ return ptr1 - _privateData;
+ ptr1--;
+ }
}
-
return B_ERROR;
}
-
-/*!
- BStringOBuf is helper classed used by _DoReplace()
-*/
-class BStringOBuf
-{
-
-public:
- BStringOBuf( uint32 startLen, float growFactor=1.5);
- ~BStringOBuf();
-
- // methods to write into buffer (always append):
- uint32 Write( const char* data, uint32 len);
-
- // getters:
- BString& TheString();
- inline bool HasData() const { return mBuf!=NULL; }
-
-private:
- bool GrowBufferToFit( uint32 len);
-
- uint32 mBufLen;
- float mGrowFactor;
- char* mBuf;
- uint32 mCurrPos;
- BString mStr;
-
- // Hide copy-constructor and assignment:
- BStringOBuf( const BStringOBuf&);
- BStringOBuf operator=( const BStringOBuf&);
-};
-
-
BString&
BString::_DoReplace(const char *findThis, const char *replaceWith, int32
maxReplaceCount,
int32 fromOffset, bool
ignoreCase)
@@ -2105,30 +2218,63 @@
? &BString::_IFindAfter
: &BString::_FindAfter;
int32 findLen = strlen( findThis);
- int32 replaceLen = replaceWith ? strlen( replaceWith) : 0;
- BStringOBuf tempIO( (int32)max_c( max_c( findLen, 128), Length()*1.2),
1.2);
+ if (!replaceWith)
+ replaceWith = "";
+ int32 replaceLen = strlen( replaceWith);
int32 lastSrcPos = fromOffset;
- int32 len;
+ PosVect positions;
for( int32 srcPos=0;
- maxReplaceCount>0 && (srcPos = (this->*findMethod)(
findThis, lastSrcPos, findLen))!=B_ERROR;
+ maxReplaceCount > 0
+ && (srcPos = (this->*findMethod)( findThis, lastSrcPos,
findLen)) >= 0;
maxReplaceCount-- ) {
- len = srcPos-lastSrcPos;
- if (fromOffset && !tempIO.HasData())
- tempIO.Write( String(), fromOffset);
- tempIO.Write( String()+lastSrcPos, len);
- tempIO.Write( replaceWith, replaceLen);
+ positions.Add( srcPos);
lastSrcPos = srcPos+findLen;
}
- if (tempIO.HasData()) {
- // only copy remainder if we have actually changed anything
- if ((len = Length()-lastSrcPos)!=0) {
- if (fromOffset && !tempIO.HasData())
- tempIO.Write( String(), fromOffset);
- tempIO.Write( String()+lastSrcPos, len);
+ _ReplaceAtPositions( &positions, findLen, replaceWith, replaceLen);
+ return *this;
+}
+
+void BString::_ReplaceAtPositions( const PosVect* positions,
+
int32 searchLen, const char* with,
+
int32 withLen)
+{
+ int32 len = Length();
+ uint32 count = positions->CountItems();
+ int32 newLength = len + count*(withLen-searchLen);
+ if (!newLength) {
+ _GrowBy( -len);
+ return;
+ }
+ int32 pos;
+ int32 lastPos = 0;
+ char* oldAdr = _privateData;
+ char* newData = (char*)malloc( newLength+sizeof(int32)+1);
+ if (newData) {
+ newData += sizeof(int32);
+ char* newAdr = newData;
+ for( uint32 i=0; i<count; ++i)
+ {
+ pos = positions->ItemAt( i);
+ len = pos-lastPos;
+ if (len>0) {
+ memcpy(newAdr, oldAdr, len);
+ oldAdr += len;
+ newAdr += len;
+ }
+ memcpy(newAdr, with, withLen);
+ oldAdr += searchLen;
+ newAdr += withLen;
+ lastPos = pos+searchLen;
}
- Adopt( tempIO.TheString());
+ len = Length()+1-lastPos;
+ if (len>0) {
+ memcpy(newAdr, oldAdr, len);
+ }
+ free( _privateData-sizeof(int32));
+ _privateData = newData;
+ _privateData[newLength] = 0;
+ _SetLength( newLength);
}
- return *this;
}
#if ENABLE_INLINES
@@ -2185,62 +2331,5 @@
ICompare(const BString *string1, const BString *string2)
{
return strcasecmp(string1->String(), string2->String());
-}
-
-
-/*----- Implementation of BStringOBuf ------------------------------*/
-BStringOBuf::BStringOBuf(uint32 startLen, float growFactor)
- :mBufLen(startLen),
- mGrowFactor(max_c((float)1.0, growFactor)),
- mBuf(NULL),
- mCurrPos(0)
-{
-}
-
-
-BStringOBuf::~BStringOBuf()
-{
- if (mBuf)
- mStr.UnlockBuffer(mCurrPos);
-}
-
-
-bool
-BStringOBuf::GrowBufferToFit(uint32 len)
-{
- if (!mBuf || mCurrPos+len > mBufLen) {
- if (mBuf) {
- mStr.UnlockBuffer(mBufLen);
- mBufLen = (uint32)max_c(mGrowFactor*mBufLen,
mGrowFactor*(mCurrPos+len));
- } else
- mBufLen = (uint32)max_c(mBufLen, mCurrPos+len);
- mBuf = mStr.LockBuffer(mBufLen);
- if (!mBuf)
- return false;
- }
- return true;
-}
-
-
-uint32
-BStringOBuf::Write(const char* data, uint32 len)
-{
- if (!len || !GrowBufferToFit( len))
- return 0;
- memcpy( mBuf+mCurrPos, data, len);
- mCurrPos += len;
- return len;
-}
-
-
-BString&
-BStringOBuf::TheString()
-{
- if (mBuf) {
- mBuf[mCurrPos] = '\0';
- mStr.UnlockBuffer( mCurrPos);
- mBuf = NULL;
- }
- return mStr;
}
Index: src/tests/kits/support/bstring/StringAppendTest.cpp
===================================================================
RCS file:
/cvsroot/open-beos/current/src/tests/kits/support/bstring/StringAppendTest.cpp,v
retrieving revision 1.2
diff -u -r1.2 StringAppendTest.cpp
--- src/tests/kits/support/bstring/StringAppendTest.cpp 15 Oct 2002 05:30:29
-0000 1.2
+++ src/tests/kits/support/bstring/StringAppendTest.cpp 6 Nov 2003 09:29:19
-0000
@@ -99,7 +99,7 @@
str1 = new BString("Base");
str1->Append("APPENDED", 40);
CPPUNIT_ASSERT(strcmp(str1->String(), "BaseAPPENDED") == 0);
- CPPUNIT_ASSERT(str1->Length() == strlen("BaseAPPENDED"));
+ CPPUNIT_ASSERT(str1->Length() == (int32)strlen("BaseAPPENDED"));
delete str1;
//char ptr is NULL
@@ -115,6 +115,25 @@
str1->Append('C', 5);
CPPUNIT_ASSERT(strcmp(str1->String(), "BaseCCCCC") == 0);
delete str1;
+
+ const int32 OUT_OF_MEM_VAL = 2*1000*1000*1000;
+#ifndef TEST_R5
+ //Append(char, int32) with excessive length:
+ NextSubTest();
+ str1 = new BString("Base");
+ str1->Append('C', OUT_OF_MEM_VAL);
+ CPPUNIT_ASSERT(strcmp(str1->String(), "Base") == 0);
+ delete str1;
+#endif
+
+#ifndef TEST_R5
+ //Append(char*, int32) with excessive length:
+ NextSubTest();
+ str1 = new BString("Base");
+ str1->Append("some more text", OUT_OF_MEM_VAL);
+ CPPUNIT_ASSERT(strcmp(str1->String(), "Basesome more text") == 0);
+ delete str1;
+#endif
}
Index: src/tests/kits/support/bstring/StringAssignTest.cpp
===================================================================
RCS file:
/cvsroot/open-beos/current/src/tests/kits/support/bstring/StringAssignTest.cpp,v
retrieving revision 1.2
diff -u -r1.2 StringAssignTest.cpp
--- src/tests/kits/support/bstring/StringAssignTest.cpp 15 Oct 2002 05:30:29
-0000 1.2
+++ src/tests/kits/support/bstring/StringAssignTest.cpp 6 Nov 2003 09:29:19
-0000
@@ -99,6 +99,25 @@
CPPUNIT_ASSERT(str->Length() == 2);
CPPUNIT_ASSERT(strcmp(newstring.String(), "") == 0);
delete str;
+
+ const int32 OUT_OF_MEM_VAL = 2*1000*1000*1000;
+#ifndef TEST_R5
+ //SetTo(char, int32) with excessive length:
+ NextSubTest();
+ str = new BString("dummy");
+ str->SetTo('C', OUT_OF_MEM_VAL);
+ CPPUNIT_ASSERT(strcmp(str->String(), "dummy") == 0);
+ delete str;
+#endif
+
+#ifndef TEST_R5
+ //SetTo(char*, int32) with excessive length:
+ NextSubTest();
+ str = new BString("dummy");
+ str->SetTo("some more text", OUT_OF_MEM_VAL);
+ CPPUNIT_ASSERT(strcmp(str->String(), "some more text") == 0);
+ delete str;
+#endif
}
Index: src/tests/kits/support/bstring/StringEscapeTest.cpp
===================================================================
RCS file:
/cvsroot/open-beos/current/src/tests/kits/support/bstring/StringEscapeTest.cpp,v
retrieving revision 1.3
diff -u -r1.3 StringEscapeTest.cpp
--- src/tests/kits/support/bstring/StringEscapeTest.cpp 19 Nov 2002 08:24:13
-0000 1.3
+++ src/tests/kits/support/bstring/StringEscapeTest.cpp 6 Nov 2003 09:29:19
-0000
@@ -17,7 +17,7 @@
void
StringEscapeTest::PerformTest(void)
{
- BString *string1, *string2;
+ BString *string1;
//CharacterEscape(char*, char)
NextSubTest();
Index: src/tests/kits/support/bstring/StringInsertTest.cpp
===================================================================
RCS file:
/cvsroot/open-beos/current/src/tests/kits/support/bstring/StringInsertTest.cpp,v
retrieving revision 1.3
diff -u -r1.3 StringInsertTest.cpp
--- src/tests/kits/support/bstring/StringInsertTest.cpp 15 Oct 2002 19:32:11
-0000 1.3
+++ src/tests/kits/support/bstring/StringInsertTest.cpp 6 Nov 2003 09:29:19
-0000
@@ -26,12 +26,15 @@
CPPUNIT_ASSERT(strcmp(str1->String(), "StrINSERTEDing") == 0);
delete str1;
- //This test crashes both implementations
- //NextSubTest();
- //str1 = new BString("String");
- //str1->Insert("INSERTED", 10);
- //CPPUNIT_ASSERT(strcmp(str1->String(), "string") == 0);
- //delete str1;
+#ifndef TEST_R5
+ // This test crashes R5 and should drop into the debugger in OpenBeOS
+ // (if compiled with DEBUG):
+ NextSubTest();
+ str1 = new BString("String");
+ str1->Insert("INSERTED", 10);
+ CPPUNIT_ASSERT(strcmp(str1->String(), "String") == 0);
+ delete str1;
+#endif
NextSubTest();
str1 = new BString;
@@ -39,6 +42,15 @@
CPPUNIT_ASSERT(strcmp(str1->String(), "NSERTED") == 0);
delete str1;
+#ifndef TEST_R5
+ // check limitation of negative values (R5 doesn't):
+ NextSubTest();
+ str1 = new BString;
+ str1->Insert("INSERTED", -142364253);
+ CPPUNIT_ASSERT(strcmp(str1->String(), "") == 0);
+ delete str1;
+#endif
+
//&Insert(const char *, int32 length, int32 pos);
NextSubTest();
str1 = new BString("string");
@@ -46,12 +58,15 @@
CPPUNIT_ASSERT(strcmp(str1->String(), "stINring") == 0);
delete str1;
- //This test crashes both implementations
- //NextSubTest();
- //str1 = new BString("string");
- //str1->Insert("INSERTED", 2, 30);
- //CPPUNIT_ASSERT(strcmp(str1->String(), "stINring") == 0);
- //delete str1;
+#ifndef TEST_R5
+ // This test crashes R5 and should drop into the debugger in OpenBeOS
+ // (if compiled with DEBUG):
+ NextSubTest();
+ str1 = new BString("string");
+ str1->Insert("INSERTED", 2, 30);
+ CPPUNIT_ASSERT(strcmp(str1->String(), "string") == 0);
+ delete str1;
+#endif
NextSubTest();
str1 = new BString("string");
@@ -71,6 +86,13 @@
str1 = new BString("string");
str1->Insert('P', 5, 3);
CPPUNIT_ASSERT(strcmp(str1->String(), "strPPPPPing") == 0);
+ delete str1;
+
+ //Insert(char c, int32 count, int32 pos)
+ NextSubTest();
+ str1 = new BString("string");
+ str1->Insert('P', 5, -2);
+ CPPUNIT_ASSERT(strcmp(str1->String(), "PPPstring") == 0);
delete str1;
//Insert(BString&)
Index: src/tests/kits/support/bstring/StringRemoveTest.cpp
===================================================================
RCS file:
/cvsroot/open-beos/current/src/tests/kits/support/bstring/StringRemoveTest.cpp,v
retrieving revision 1.4
diff -u -r1.4 StringRemoveTest.cpp
--- src/tests/kits/support/bstring/StringRemoveTest.cpp 10 Jan 2003 16:10:00
-0000 1.4
+++ src/tests/kits/support/bstring/StringRemoveTest.cpp 6 Nov 2003 09:29:20
-0000
@@ -86,11 +86,11 @@
CPPUNIT_ASSERT(strcmp(string1->String(), "a String") == 0);
delete string1;
- //from + length is > Length()
+ //from + length exceeds Length() (R5 fails)
NextSubTest();
string1 = new BString("a String");
string1->Remove(4, 30);
- CPPUNIT_ASSERT(strcmp(string1->String(), "a String") == 0);
+ CPPUNIT_ASSERT(strcmp(string1->String(), "a St") == 0);
delete string1;
NextSubTest();
@@ -223,7 +223,7 @@
string2 = new BString("string");
string2->MoveInto(*string1, 0, 200);
CPPUNIT_ASSERT(strcmp(string1->String(), "string") == 0);
- CPPUNIT_ASSERT(strcmp(string2->String(), "string") == 0);
+ CPPUNIT_ASSERT(strcmp(string2->String(), "") == 0);
delete string1;
delete string2;
@@ -242,7 +242,7 @@
memset(dest, 0, 100);
string1->MoveInto(dest, 0, 50);
CPPUNIT_ASSERT(strcmp(dest, "some text") == 0);
- CPPUNIT_ASSERT(strcmp(string1->String(), "some text") == 0);
+ CPPUNIT_ASSERT(strcmp(string1->String(), "") == 0);
delete string1;
}
Index: src/tests/kits/support/bstring/StringReplaceTest.cpp
===================================================================
RCS file:
/cvsroot/open-beos/current/src/tests/kits/support/bstring/StringReplaceTest.cpp,v
retrieving revision 1.6
diff -u -r1.6 StringReplaceTest.cpp
--- src/tests/kits/support/bstring/StringReplaceTest.cpp 11 Feb 2003
19:14:04 -0000 1.6
+++ src/tests/kits/support/bstring/StringReplaceTest.cpp 6 Nov 2003
09:29:20 -0000
@@ -17,7 +17,9 @@
void
StringReplaceTest::PerformTest(void)
{
- BString *str1, *str2;
+ BString *str1;
+ const int32 sz = 1024*50;
+ char* buf;
//&ReplaceFirst(char, char);
NextSubTest();
@@ -257,10 +259,79 @@
//ReplaceSet(const char*, const char*)
NextSubTest();
str1 = new BString("abcd abcd abcd");
+ str1->ReplaceSet("abcd ", "");
+ CPPUNIT_ASSERT(strcmp(str1->String(), "") == 0);
+ delete str1;
+#endif
+
+#ifndef TEST_R5
+ //ReplaceSet(const char*, const char*)
+ NextSubTest();
+ str1 = new BString("abcd abcd abcd");
str1->ReplaceSet("ad", "da");
CPPUNIT_ASSERT(strcmp(str1->String(), "dabcda dabcda dabcda") == 0);
delete str1;
#endif
+
+#ifndef TEST_R5
+ //ReplaceSet(const char*, const char*)
+ NextSubTest();
+ str1 = new BString("abcd abcd abcd");
+ str1->ReplaceSet("ad", "");
+ CPPUNIT_ASSERT(strcmp(str1->String(), "bc bc bc") == 0);
+ delete str1;
+#endif
+
+ // we repeat some test, but this time with a bit of data
+ // to test the performance:
+
+ // ReplaceSet(const char*, const char*)
+ NextSubTest();
+ str1 = new BString();
+ buf = str1->LockBuffer(sz);
+ memset( buf, 'x', sz);
+ str1->UnlockBuffer( sz);
+ str1->ReplaceSet("x", "y");
+ CPPUNIT_ASSERT(str1->Length() == sz);
+ delete str1;
+
+ NextSubTest();
+ str1 = new BString();
+ buf = str1->LockBuffer(sz);
+ memset( buf, 'x', sz);
+ str1->UnlockBuffer( sz);
+ str1->ReplaceSet("x", "");
+ CPPUNIT_ASSERT(str1->Length() == 0);
+ delete str1;
+
+ // ReplaceAll(const char*, const char*)
+ NextSubTest();
+ str1 = new BString();
+ buf = str1->LockBuffer(sz);
+ memset( buf, 'x', sz);
+ str1->UnlockBuffer( sz);
+ str1->ReplaceAll("x", "y");
+ CPPUNIT_ASSERT(str1->Length() == sz);
+ delete str1;
+
+ NextSubTest();
+ str1 = new BString();
+ buf = str1->LockBuffer(sz);
+ memset( buf, 'x', sz);
+ str1->UnlockBuffer( sz);
+ str1->ReplaceAll("xx", "y");
+ CPPUNIT_ASSERT(str1->Length() == sz/2);
+ delete str1;
+
+ NextSubTest();
+ str1 = new BString();
+ buf = str1->LockBuffer(sz);
+ memset( buf, 'x', sz);
+ str1->UnlockBuffer( sz);
+ str1->ReplaceSet("xx", "");
+ CPPUNIT_ASSERT(str1->Length() == 0);
+ delete str1;
+
}
Index: src/tests/kits/support/bstring/StringSearchTest.cpp
===================================================================
RCS file:
/cvsroot/open-beos/current/src/tests/kits/support/bstring/StringSearchTest.cpp,v
retrieving revision 1.8
diff -u -r1.8 StringSearchTest.cpp
--- src/tests/kits/support/bstring/StringSearchTest.cpp 9 Aug 2003 04:30:43
-0000 1.8
+++ src/tests/kits/support/bstring/StringSearchTest.cpp 6 Nov 2003 09:29:20
-0000
@@ -56,7 +56,7 @@
NextSubTest();
string1 = new BString("string");
i = string1->FindFirst((char*)NULL);
- CPPUNIT_ASSERT(i == B_BAD_VALUE);
+ CPPUNIT_ASSERT(i == B_ERROR);
delete string1;
#endif
@@ -109,7 +109,7 @@
NextSubTest();
string1 = new BString("abc abc abc");
i = string1->FindFirst((char*)NULL, 3);
- CPPUNIT_ASSERT(i == B_BAD_VALUE);
+ CPPUNIT_ASSERT(i == B_ERROR);
delete string1;
#endif
@@ -180,7 +180,7 @@
NextSubTest();
string1 = new BString("string");
i = string1->FindLast((char*)NULL);
- CPPUNIT_ASSERT(i == B_BAD_VALUE);
+ CPPUNIT_ASSERT(i == B_ERROR);
delete string1;
#endif
@@ -219,7 +219,7 @@
NextSubTest();
string1 = new BString("abc abc abc");
i = string1->FindLast((char*)NULL, 3);
- CPPUNIT_ASSERT(i == B_BAD_VALUE);
+ CPPUNIT_ASSERT(i == B_ERROR);
delete string1;
#endif
@@ -312,7 +312,7 @@
NextSubTest();
string1 = new BString("string");
i = string1->IFindFirst((char*)NULL);
- CPPUNIT_ASSERT(i == B_BAD_VALUE);
+ CPPUNIT_ASSERT(i == B_ERROR);
delete string1;
#endif
@@ -427,7 +427,7 @@
NextSubTest();
string1 = new BString("string");
i = string1->IFindLast((char*)NULL);
- CPPUNIT_ASSERT(i == B_BAD_VALUE);
+ CPPUNIT_ASSERT(i == B_ERROR);
delete string1;
#endif
- Follow-Ups:
- [interfacekit] R3 legacy code in R5 drivers?!?
- From: Rudolf
- [interfacekit] Re: A patch for BString
- From: Ingo Weinhold
Other related posts:
- » [interfacekit] A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- » [interfacekit] Re: A patch for BString
- [interfacekit] R3 legacy code in R5 drivers?!?
- From: Rudolf
- [interfacekit] Re: A patch for BString
- From: Ingo Weinhold