]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Tied more closely SBuf and MemBlob size_type
authorFrancesco Chemolli <kinkie@squid-cache.org>
Fri, 26 Jul 2013 09:20:09 +0000 (11:20 +0200)
committerFrancesco Chemolli <kinkie@squid-cache.org>
Fri, 26 Jul 2013 09:20:09 +0000 (11:20 +0200)
Better compliance with standards
Improved SBuf documentation
Improved adherence to std::string method signatures
Improved \0-cleanliness
Removed some methods taking std::string arguments to avoid double data copies,
  documented alternate patterns
Implemented cmp and caseCmp shortcuts
Cleaned-up some methods' implementations after Alex Rousskov's suggestions
Improved unit tests' cleanliness by making more effective use of cppunit macros
Implemented more unit tests, better coverage for \0-cleanliness

src/SBuf.cc
src/SBuf.h
src/SBufStream.h
src/tests/SBufFindTest.cc
src/tests/testSBuf.cc
src/tests/testSBuf.h

index 42520b4fe070c13ce0576e1d1907739399acfbee..ae47f36eeb4739440d1db82765ad870a0b44b141 100644 (file)
@@ -60,6 +60,8 @@
 InstanceIdDefinitions(SBuf, "SBuf");
 
 SBufStats SBuf::stats;
+const SBuf::size_type SBuf::npos;
+const SBuf::size_type SBuf::maxSize;
 
 SBufStats::SBufStats()
         : alloc(0), allocCopy(0), allocFromString(0), allocFromCString(0),
@@ -119,7 +121,7 @@ SBuf::SBuf(const String &S)
         : store_(GetStorePrototype()), off_(0), len_(0)
 {
     debugs(24, 8, id << " created from string");
-    assign(S.rawBuf(), 0, S.size());
+    assign(S.rawBuf(), S.size());
     ++stats.alloc;
     ++stats.allocFromString;
     ++stats.live;
@@ -128,17 +130,17 @@ SBuf::SBuf(const String &S)
 SBuf::SBuf(const std::string &s)
         : store_(GetStorePrototype()), off_(0), len_(0)
 {
-    debugs(24, 8, id << " created from string");
-    assign(s.data(),0,s.size());
+    debugs(24, 8, id << " created from std::string");
+    lowAppend(s.data(),s.length());
     ++stats.alloc;
     ++stats.allocFromString;
     ++stats.live;
 }
 
-SBuf::SBuf(const char *S, size_type pos, size_type n)
+SBuf::SBuf(const char *S, size_type n)
         : store_(GetStorePrototype()), off_(0), len_(0)
 {
-    append(S,pos,n); //bounds checked in append()
+    append(S,n);
     ++stats.alloc;
     ++stats.allocFromCString;
     ++stats.live;
@@ -153,11 +155,7 @@ SBuf::~SBuf()
 MemBlob::Pointer
 SBuf::GetStorePrototype()
 {
-    static MemBlob::Pointer InitialStore = NULL;
-    if (InitialStore == NULL) {
-        static char lowPrototype[] = "";
-        InitialStore = new MemBlob(lowPrototype, 0);
-    }
+    static MemBlob::Pointer InitialStore = new MemBlob(0);
     return InitialStore;
 }
 
@@ -175,11 +173,11 @@ SBuf::assign(const SBuf &S)
 }
 
 SBuf&
-SBuf::assign(const char *S, size_type pos, size_type n)
+SBuf::assign(const char *S, size_type n)
 {
-    debugs(24, 6, id << " from c-string, pos=" << pos << "n=" << n << ")");
+    debugs(24, 6, id << " from c-string, n=" << n << ")");
     clear();
-    return append(S, pos, n); //bounds checked in append()
+    return append(S, n); //bounds checked in append()
 }
 
 void
@@ -228,41 +226,20 @@ SBuf::clear()
 SBuf&
 SBuf::append(const SBuf &S)
 {
-    return append(S.buf(), 0, S.length());
+    return lowAppend(S.buf(), S.length());
 }
 
-SBuf&
-SBuf::append(const char * S, size_type pos, size_type n)
+SBuf &
+SBuf::append(const char * S, size_type Ssize)
 {
-    Must(pos == npos || pos >= 0);
-    Must(n == npos || n >= 0);
+    Must (Ssize == npos || Ssize >= 0);
 
     if (S == NULL)
         return *this;
-    if (n == npos)
-        n = strlen(S)-pos;
-
+    if (Ssize == npos)
+        Ssize = strlen(S);
     debugs(24, 7, "from c-string to id " << id);
-
-    reserveSpace(n); //called method also checks n <= maxSize()
-    const char *actual_start = S+pos;
-    store_->append(actual_start, n);
-    len_ += n;
-    ++stats.append;
-    return *this;
-}
-
-SBuf&
-SBuf::append(const std::string &str, SBuf::size_type pos, SBuf::size_type n)
-{
-    return append(str.data(), pos, n); //bounds checked in append()
-}
-
-SBuf&
-SBuf::assign(const std::string &str, size_type pos, size_type n)
-{
-    clear();
-    return append(str, pos, n); //bounds checked in append()
+    return lowAppend(S, Ssize);
 }
 
 SBuf&
@@ -296,7 +273,7 @@ SBuf::vappendf(const char *fmt, va_list vargs)
 
     Must(fmt != NULL);
 
-    //we can assume that we'll need to append at least strlen(fmt) bytes,
+    //reserve twice the format-string size, it's a likely heuristic
     reserveSpace(strlen(fmt)*2);
 
     while (length() <= maxSize) {
@@ -358,12 +335,12 @@ SBuf::dump(std::ostream &os) const
     << ",len:" << len_
     << ") : '";
     print(os);
-    os << std::endl;
+    os << '\'' << std::endl;
     return os;
 }
 
 void
-SBuf::setAt(SBuf::size_type pos, char toset)
+SBuf::setAt(size_type pos, char toset)
 {
     checkAccessBounds(pos);
     cow();
@@ -371,26 +348,45 @@ SBuf::setAt(SBuf::size_type pos, char toset)
     ++stats.setChar;
 }
 
+static int
+memcasecmp(const char *b1, const char *b2, SBuf::size_type len)
+{
+    int rv=0;
+    while (len > 0) {
+        rv = tolower(*b1)-tolower(*b2);
+        if (rv != 0)
+            return rv;
+        ++b1;
+        ++b2;
+        --len;
+    }
+    return rv;
+}
+
 int
 SBuf::compare(const SBuf &S, SBufCaseSensitive isCaseSensitive, size_type n) const
 {
     Must(n == npos || n >= 0);
+    if (n != npos) {
+        if (n > length())
+            return compare(S.substr(0,n),isCaseSensitive);
+        return substr(0,n).compare(S.substr(0,n),isCaseSensitive);
+    }
+    size_type byteCompareLen = min(S.length(), length());
     ++stats.compareSlow;
-    size_type sz = min(S.length(), length());
-    if (n != npos)
-        sz = min(n, sz);
-    int rv;
-    if (isCaseSensitive == caseSensitive)
-        rv = strncmp(buf(), S.buf(), sz);
-    else
-        rv = strncasecmp(buf(), S.buf(), sz);
+    int rv = 0;
+    if (isCaseSensitive == caseSensitive) {
+        rv = memcmp(buf(), S.buf(), byteCompareLen);
+    } else {
+        rv = memcasecmp(buf(), S.buf(), byteCompareLen);
+    }
     if (rv != 0)
         return rv;
-    //if max-length was specified, it was hit, and the tail is ignored.
-    if (n != npos)
+    if (length() == S.length())
         return 0;
-    //first sz bytes equal. longest string "wins"
-    return commonCompareChecksPost(S);
+    if (length() > S.length())
+        return 1;
+    return -1;
 }
 
 bool
@@ -421,7 +417,7 @@ SBuf::operator ==(const SBuf & S) const
         return true;  //shortcut: same store, offset and length
     }
     ++stats.compareSlow;
-    const bool rv = (0 == strncmp(buf(), S.buf(), length()));
+    const bool rv = (0 == memcmp(buf(), S.buf(), length()));
     debugs(24, 8, "returning " << rv);
     return rv;
 }
@@ -433,7 +429,7 @@ SBuf::operator !=(const SBuf & S) const
 }
 
 SBuf
-SBuf::consume(SBuf::size_type n)
+SBuf::consume(size_type n)
 {
     Must (n == npos || n >= 0);
     if (n == npos)
@@ -452,11 +448,11 @@ SBufStats& SBuf::GetStats()
 }
 
 SBuf::size_type
-SBuf::copy(char *dest, SBuf::size_type n) const
+SBuf::copy(char *dest, size_type n) const
 {
     Must(n >= 0);
 
-    SBuf::size_type toexport = min(n,length());
+    size_type toexport = min(n,length());
     memcpy(dest, buf(), toexport);
     ++stats.copyOut;
     return toexport;
@@ -478,9 +474,11 @@ SBuf::rawSpace(size_type minSize)
 }
 
 void
-SBuf::forceSize(SBuf::size_type newSize)
+SBuf::forceSize(size_type newSize)
 {
     Must(store_->LockCount() == 1);
+    if (newSize > min(maxSize,store_->capacity-off_))
+        throw SBufTooBigException(__FILE__,__LINE__);
     len_ = newSize;
     store_->size = newSize;
 }
@@ -499,7 +497,7 @@ SBuf::c_str()
 }
 
 SBuf&
-SBuf::chop(SBuf::size_type pos, SBuf::size_type n)
+SBuf::chop(size_type pos, size_type n)
 {
     if (pos != npos && pos < 0)
         pos = 0;
@@ -543,7 +541,7 @@ SBuf::trim(const SBuf &toRemove, bool atBeginning, bool atEnd)
 }
 
 SBuf
-SBuf::substr(SBuf::size_type pos, SBuf::size_type n) const
+SBuf::substr(size_type pos, size_type n) const
 {
     SBuf rv(*this);
     rv.chop(pos, n); //stats handled by callee
@@ -551,16 +549,18 @@ SBuf::substr(SBuf::size_type pos, SBuf::size_type n) const
 }
 
 SBuf::size_type
-SBuf::find(char c, SBuf::size_type startPos) const
+SBuf::find(char c, size_type startPos) const
 {
     ++stats.find;
 
-    if (startPos == SBuf::npos)
-        return SBuf::npos;
+    // for npos with char sd::string returns npos
+    // this differs from how std::string handles 1-length string
+    if (startPos == npos)
+        return npos;
 
     // std::string returns npos if needle is outside hay
     if (startPos >= length())
-        return SBuf::npos;
+        return npos;
 
     // ignore invalid startPos
     if (startPos < 0)
@@ -569,7 +569,7 @@ SBuf::find(char c, SBuf::size_type startPos) const
     const void *i = memchr(buf()+startPos, (int)c, (size_type)length()-startPos);
 
     if (i == NULL)
-        return SBuf::npos;
+        return npos;
 
     return (static_cast<const char *>(i)-buf());
 }
@@ -577,34 +577,35 @@ SBuf::find(char c, SBuf::size_type startPos) const
 SBuf::size_type
 SBuf::find(const SBuf &needle, size_type startPos) const
 {
-    // if needle length is 1 use the char search. Stats updated there
-    if (needle.length() == 1)
-        return find(needle[0], startPos);
-
-    // if needle length is 1, the stats were
-    ++stats.find;
-
-    if (startPos == SBuf::npos)
-        return SBuf::npos;
-
     // std::string allows needle to overhang hay but not start outside
-    if (startPos > length())
-        return SBuf::npos;
-
-    // ignore invalid startPos
-    if (startPos < 0)
-        startPos = 0;
+    if (startPos != npos && startPos > length()) {
+        ++stats.find;
+        return npos;
+    }
 
     // for empty needle std::string returns startPos
-    if (needle.length() == 0)
+    if (needle.length() == 0) {
+        ++stats.find;
         return startPos;
+    }
+
+    // for npos with char* std::string scans entire hay
+    // this differs from how std::string handles single char from npos
+    if (startPos == npos)
+        return npos;
+
+    // if needle length is 1 use the char search
+    if (needle.length() == 1)
+        return find(needle[0], startPos);
+
+    ++stats.find;
 
     char *begin = buf()+startPos;
     char *lastPossible = buf()+length()-needle.length()+1;
     char needleBegin = needle[0];
 
     debugs(24, 7, "looking for " << needle << "starting at " << startPos <<
-           " in id " << id);
+                    " in id " << id);
     while (begin < lastPossible) {
         char *tmp;
         debugs(24, 8, " begin=" << (void *) begin <<
@@ -612,7 +613,7 @@ SBuf::find(const SBuf &needle, size_type startPos) const
         tmp = static_cast<char *>(memchr(begin, needleBegin, lastPossible-begin));
         if (tmp == NULL) {
             debugs(24, 8 , "First byte not found");
-            return SBuf::npos;
+            return npos;
         }
         // lastPossible guarrantees no out-of-bounds with memcmp()
         if (0 == memcmp(needle.buf(), tmp, needle.length())) {
@@ -622,7 +623,7 @@ SBuf::find(const SBuf &needle, size_type startPos) const
         begin = tmp+1;
     }
     debugs(24, 8, "not found");
-    return SBuf::npos;
+    return npos;
 }
 
 SBuf::size_type
@@ -635,24 +636,21 @@ SBuf::rfind(const SBuf &needle, SBuf::size_type endPos) const
     ++stats.find;
 
     // on npos input std::string scans from the end of hay
-    if (endPos == SBuf::npos || endPos > length())
+    if (endPos == npos || endPos > length())
         endPos=length();
 
     // on empty hay std::string returns npos
     if (length() < needle.length())
-        return SBuf::npos;
-
-    if (endPos < 0)
-        return SBuf::npos;
+        return npos;
 
     // on empty needle std::string returns the position the search starts
     if (needle.length() == 0)
         return endPos;
 
-    /* std::string permits needle to overhang endPos
-        if (endPos <= needle.length())
-            return npos;
-    */
+/* std::string permits needle to overhang endPos
+    if (endPos <= needle.length())
+        return npos;
+*/
 
     char *bufBegin = buf();
     char *cur = bufBegin+endPos;
@@ -675,26 +673,26 @@ SBuf::rfind(char c, SBuf::size_type endPos) const
     ++stats.find;
 
     // on empty hay std::string returns size of hay
-    if (length() < 1)
-        return SBuf::npos;
+    if (length() == 0)
+        return npos;
 
     // on npos input std::string compares last octet of hay
-    if (endPos == SBuf::npos || endPos >= length()) {
-        endPos=length();
-    } else if (endPos < 0 ) {
-        return SBuf::npos;
+    if (endPos == npos || endPos >= length()) {
+        endPos = length();
+    } else if (endPos < 0) {
+        return npos;
     } else {
         // NP: off-by-one weirdness:
         // endPos is an offset ... 0-based
         // length() is a count ... 1-based
-        // memrchr() requires a 1-based count of space to scan.
+        // memrhr() requires a 1-based count of space to scan.
         ++endPos;
     }
 
     const void *i = memrchr(buf(), (int)c, (size_type)endPos);
 
     if (i == NULL)
-        return SBuf::npos;
+        return npos;
 
     return (static_cast<const char *>(i)-buf());
 }
@@ -709,10 +707,10 @@ SBuf::find_first_of(const SBuf &set, size_type startPos) const
     ++stats.find;
 
     if (startPos == npos)
-        return SBuf::npos;
+        return npos;
 
     if (startPos > length())
-        return SBuf::npos;
+        return npos;
 
     if (startPos < 0)
         startPos = 0;
@@ -728,7 +726,7 @@ SBuf::find_first_of(const SBuf &set, size_type startPos) const
         ++cur;
     }
     debugs(24, 7, "not found");
-    return SBuf::npos;
+    return npos;
 }
 
 /*
@@ -816,7 +814,7 @@ SBuf::toUpper() const
  * \throw OutOfBoundsException if access is out of bounds
  */
 void
-SBuf::checkAccessBounds(SBuf::size_type pos) const
+SBuf::checkAccessBounds(size_type pos) const
 {
     if (pos < 0)
         throw OutOfBoundsException(*this, pos, __FILE__, __LINE__);
@@ -842,7 +840,7 @@ SBuf::toString() const
  * algorithms in MemBlock, it is guarranteed NOT to be smaller.
  */
 void
-SBuf::reAlloc(SBuf::size_type newsize)
+SBuf::reAlloc(size_type newsize)
 {
     debugs(24, DBG_DATA, "new size: " << newsize);
     if (newsize > maxSize)
@@ -855,3 +853,36 @@ SBuf::reAlloc(SBuf::size_type newsize)
     ++stats.cowSlow;
     debugs(24, 7, "new store capacity: " << store_->capacity);
 }
+
+SBuf&
+SBuf::lowAppend(const char * memArea, size_type areaSize)
+{
+    reserveSpace(areaSize); //called method also checks n <= maxSize()
+    store_->append(memArea, areaSize);
+    len_ += areaSize;
+    ++stats.append;
+    return *this;
+}
+
+/**
+ * copy-on-write: make sure that we are the only holder of the backing store.
+ * If not, reallocate. If a new size is specified, and it is greater than the
+ * current length, the backing store will be extended as needed
+ * \retval false no grow was needed
+ * \retval true had to copy
+ */
+bool
+SBuf::cow(SBuf::size_type newsize)
+{
+    debugs(24, DBG_DATA, "new size:" << newsize);
+    if (newsize == npos || newsize < length())
+        newsize = length();
+
+    if (store_->LockCount() == 1 && newsize == length()) {
+        debugs(24, DBG_DATA, "no cow needed");
+        ++stats.cowFast;
+        return false;
+    }
+    reAlloc(newsize);
+    return true;
+}
index 678725d0004dab1cfeda4a34f1dbdf7956f43ee8..60708d3bbae3e9dac6caea0130dd4b7d2c3a4693 100644 (file)
@@ -32,8 +32,6 @@
 #define SQUID_SBUF_H
 
 #include "base/InstanceId.h"
-// Debug.h only needed for for SBuf::cow() debug statements.
-#include "Debug.h"
 #include "MemBlob.h"
 #include "SBufExceptions.h"
 #include "SquidString.h"
@@ -74,28 +72,28 @@ typedef enum {
 class SBufStats
 {
 public:
-    u_int64_t alloc; ///<number of calls to SBuf constructors
-    u_int64_t allocCopy; ///<number of calls to SBuf copy-constructor
-    u_int64_t allocFromString; ///<number of copy-allocations from Strings
-    u_int64_t allocFromCString; ///<number of copy-allocations from c-strings
-    u_int64_t assignFast; ///<number of no-copy assignment operations
-    u_int64_t clear; ///<number of clear operations
-    u_int64_t append; ///<number of append operations
-    u_int64_t toStream;  ///<number of write operations to ostreams
-    u_int64_t setChar; ///<number of calls to setAt
-    u_int64_t getChar; ///<number of calls to at() and operator[]
-    u_int64_t compareSlow; ///<number of comparison operations requiring data scan
-    u_int64_t compareFast; ///<number of comparison operations not requiring data scan
-    u_int64_t copyOut; ///<number of data-copies to other forms of buffers
-    u_int64_t rawAccess; ///<number of accesses to raw contents
-    u_int64_t chop;  ///<number of chop operations
-    u_int64_t trim;  ///<number of trim operations
-    u_int64_t find;  ///<number of find operations
-    u_int64_t scanf;  ///<number of scanf operations
-    u_int64_t caseChange; ///<number of toUpper and toLower operations
-    u_int64_t cowFast; ///<number of cow operations not actually requiring a copy
-    u_int64_t cowSlow; ///<number of cow operations requiring a copy
-    u_int64_t live;  ///<number of currently-allocated SBuf
+    uint64_t alloc; ///<number of calls to SBuf constructors
+    uint64_t allocCopy; ///<number of calls to SBuf copy-constructor
+    uint64_t allocFromString; ///<number of copy-allocations from Strings
+    uint64_t allocFromCString; ///<number of copy-allocations from c-strings
+    uint64_t assignFast; ///<number of no-copy assignment operations
+    uint64_t clear; ///<number of clear operations
+    uint64_t append; ///<number of append operations
+    uint64_t toStream;  ///<number of write operations to ostreams
+    uint64_t setChar; ///<number of calls to setAt
+    uint64_t getChar; ///<number of calls to at() and operator[]
+    uint64_t compareSlow; ///<number of comparison operations requiring data scan
+    uint64_t compareFast; ///<number of comparison operations not requiring data scan
+    uint64_t copyOut; ///<number of data-copies to other forms of buffers
+    uint64_t rawAccess; ///<number of accesses to raw contents
+    uint64_t chop;  ///<number of chop operations
+    uint64_t trim;  ///<number of trim operations
+    uint64_t find;  ///<number of find operations
+    uint64_t scanf;  ///<number of scanf operations
+    uint64_t caseChange; ///<number of toUpper and toLower operations
+    uint64_t cowFast; ///<number of cow operations not actually requiring a copy
+    uint64_t cowSlow; ///<number of cow operations requiring a copy
+    uint64_t live;  ///<number of currently-allocated SBuf
 
     ///Dump statistics to an ostream.
     std::ostream& dump(std::ostream &os) const;
@@ -113,7 +111,7 @@ public:
 class SBuf
 {
 public:
-    typedef int32_t size_type;
+    typedef MemBlob::size_type size_type;
     static const size_type npos = -1;
 
     /// Maximum size of a SBuf. By design it MUST be < MAX(size_type)/2. Currently 256Mb.
@@ -128,13 +126,12 @@ public:
      * Create a new SBuf containing a COPY of the contents of the
      * c-string
      * \param S the c string to be copied
-     * \param pos how many bytes to skip at the beginning of the c-string
-     * \param n how many bytes to import into the SBuf. If it is SBuf::npos
+     * \param n how many bytes to import into the SBuf. If it is npos
      *              or unspecified, imports to end-of-cstring
      * \note it is the caller's responsibility not to go out of bounds
      * \note bounds is 0 <= pos < length()
      */
-    explicit SBuf(const char *S, size_type pos = 0, size_type n = npos);
+    explicit SBuf(const char *S, size_type n = npos);
 
     /** Constructor: import SquidString, copying contents.
      *
@@ -163,29 +160,22 @@ public:
      *
      * It is the caller's duty to free the imported string, if needed.
      * \param S the c string to be copied
-     * \param pos how many bytes to skip at the beginning of the c-string.
-     * \param n how many bytes to import into the SBuf. If it is SBuf::npos
+     * \param n how many bytes to import into the SBuf. If it is npos
      *              or unspecified, imports to end-of-cstring
      * \note it is the caller's responsibility not to go out of bounds
-     * \note bounds is 0 <= pos < length()
+     * \note to assign a std::string use the pattern:
+     *    assign(stdstr.data(), stdstd.length())
      */
-    SBuf& assign(const char *S, size_type pos = 0, size_type n = npos);
+    SBuf& assign(const char *S, size_type n = npos);
 
     /** Assignment operator. Copy a NULL-terminated c-style string into a SBuf.
      *
      * Copy a c-style string into a SBuf. Shortcut for SBuf.assign(S)
      * It is the caller's duty to free the imported string, if needed.
+     * \note not \0-clean
      */
     SBuf& operator =(const char *S) {return assign(S);}
 
-    /** Import a std::string into a SBuf. Contents are copied.
-     *
-     * \param pos skip this many bytes at the beginning of string.
-     *          0 is beginning-of-string
-     * \param n how many bytes to copy. Default is SBuf::npos, end-of-string.
-     */
-    SBuf& assign(const std::string &s, size_type pos = 0, size_type n = npos);
-
     /** reset the SBuf as if it was just created.
      *
      * Resets the SBuf to empty, memory is freed lazily.
@@ -205,21 +195,12 @@ public:
      *
      * \param S the c string to be copied. Can be NULL.
      * \param pos how many bytes to skip at the beginning of the c-string
-     * \param n how many bytes to import into the SBuf. If it is SBuf::npos
-     *              or unspecified, imports to end-of-cstring
-     */
-    SBuf& append(const char * S, size_type pos = 0, size_type n = npos);
-
-    /** Append operation for std::string
-     *
-     * Append the supplied std::string to the SBuf; extend storage as needed.
-     *
-     * \param string the std::string to be copied.
-     * \param pos how many bytes to skip at the beginning of the c-string
-     * \param n how many bytes to import into the SBuf. If it is SBuf::npos
+     * \param n how many bytes to import into the SBuf. If it is npos
      *              or unspecified, imports to end-of-cstring
+     * \note to append a std::string use the pattern
+     *     cstr_append(stdstr.data(), stdstd.length())
      */
-    SBuf& append(const std::string &str, size_type pos = 0, size_type n = npos);
+    SBuf& append(const char * S, size_type Ssize = npos);
 
     /** Assignment operation with printf(3)-style definition
      * \note arguments may be evaluated more than once, be careful
@@ -275,12 +256,22 @@ public:
     /** compare to other SBuf, str(case)cmp-style
      *
      * \param isCaseSensitive one of caseSensitive or caseInsensitive
-     * \param n compare up to this many bytes. if npos (default), to end-of-string
+     * \param n compare up to this many bytes. if npos (default), compare whole SBufs
      * \retval >0 argument of the call is greater than called SBuf
      * \retval <0 argument of the call is smaller than called SBuf
      * \retval 0  argument of the call has the same contents of called SBuf
      */
-    int compare(const SBuf &S, SBufCaseSensitive isCaseSensitive = caseSensitive, size_type n = npos) const;
+    int compare(const SBuf &S, SBufCaseSensitive isCaseSensitive, size_type n = npos) const;
+
+    /// shorthand version for compare
+    inline int cmp(const SBuf &S, size_type n = npos) const {
+        return compare(S,caseSensitive,n);
+    }
+
+    /// shorthand version for case-insensitive comparison
+    inline int caseCmp(const SBuf &S, size_type n = npos) const {
+        return compare(S,caseInsensitive,n);
+    }
 
     /** check whether the entire supplied argument is a prefix of the SBuf.
      *  \param S the prefix to match against
@@ -291,10 +282,10 @@ public:
 
     bool operator ==(const SBuf & S) const;
     bool operator !=(const SBuf & S) const;
-    bool operator <(const SBuf &S) const {return (compare(S) < 0);}
-    bool operator >(const SBuf &S) const {return (compare(S) > 0);}
-    bool operator <=(const SBuf &S) const {return (compare(S) <= 0);}
-    bool operator >=(const SBuf &S) const {return (compare(S) >= 0);}
+    bool operator <(const SBuf &S) const {return (cmp(S) < 0);}
+    bool operator >(const SBuf &S) const {return (cmp(S) > 0);}
+    bool operator <=(const SBuf &S) const {return (cmp(S) <= 0);}
+    bool operator >=(const SBuf &S) const {return (cmp(S) >= 0);}
 
     /** Consume bytes at the head of the SBuf
      *
@@ -302,7 +293,7 @@ public:
      * whichever is shorter. If more bytes are consumed than available,
      * the SBuf is emptied
      * \param n how many bytes to remove; could be zero.
-     *     SBuf::npos (or no argument) means 'to the end of SBuf'
+     *     npos (or no argument) means 'to the end of SBuf'
      * \return a new SBuf containing the consumed bytes.
      */
     SBuf consume(size_type n = npos);
@@ -368,7 +359,8 @@ public:
      *
      * Adapt the SBuf internal state after external interference
      * such as writing into it via rawSpace.
-     * \throw TextException if we
+     * \throw TextException if SBuf doesn't have exclusive ownership of store
+     * \throw SBufTooBigException if new size is bigger than available store space
      */
     void forceSize(size_type newSize);
 
@@ -414,8 +406,9 @@ public:
     /** Request to extend the SBuf's free store space.
      *
      * After the reserveSpace request, the SBuf is guaranteed to have at
-     * least minSpace bytes of unused backing store
-     * following the currently used portion
+     * least minSpace bytes of unused backing store following the currently
+     * used portion until the next append operation to any of the SBufs
+     * sharing the backing MemBlob
      * \throw SBufTooBigException if the user tries to allocate too big a SBuf
      */
     void reserveSpace(size_type minSpace);
@@ -423,7 +416,8 @@ public:
     /** Request to resize the SBuf's store
      *
      * After this method is called, the SBuf is guaranteed to have at least
-     * minCapacity bytes of total space, including the currently-used portion
+     * minCapacity bytes of total buffer size, including the currently-used
+     * portion
      * \throw SBufTooBigException if the user tries to allocate too big a SBuf
      */
     void reserveCapacity(size_type minCapacity);
@@ -437,7 +431,7 @@ public:
      *      npos or it is greater than the SBuf length, the SBuf is cleared and
      *      an empty SBuf is returned. If it is <0, it is ignored
      * \param n maximum number of bytes of the resulting SBuf.
-     *     SBuf::npos means "to end of SBuf".
+     *     npos means "to end of SBuf".
      *     if it is 0, the SBuf is cleared and an empty SBuf is returned.
      *     if it is < 0, it is ignored (same as supplying npos)
      *     if it overflows the end of the SBuf, it is capped to the end of SBuf
@@ -465,10 +459,10 @@ public:
     /** Find first occurrence of character in SBuf
      *
      * Returns the index in the SBuf of the first occurrence of char c.
-     * \return SBuf::npos if the char was not found
+     * \return npos if the char was not found
      * \param startPos if specified, ignore any occurrences before that position
      *     if startPos is npos or greater than length() npos is always returned
-     *     if startPos is < 0, it is ignored
+     *     if startPos is less than zero, it is ignored
      */
     size_type find(char c, size_type startPos = 0) const;
 
@@ -479,14 +473,14 @@ public:
      * \param startPos if specified, ignore any occurrences before that position
      *     if startPos is npos or greater than length() npos is always returned
      *     if startPos is < 0, it is ignored
-     * \return SBuf::npos if the SBuf was not found
+     * \return npos if the SBuf was not found
      */
     size_type find(const SBuf & str, size_type startPos = 0) const;
 
     /** Find last occurrence of character in SBuf
      *
      * Returns the index in the SBuf of the last occurrence of char c.
-     * \return SBuf::npos if the char was not found
+     * \return npos if the char was not found
      * \param endPos if specified, ignore any occurrences after that position.
      *   if npos or greater than length(), the whole SBuf is considered
      *   if < 0, npos is always returned
@@ -497,7 +491,7 @@ public:
      *
      * Returns the index in the SBuf of the last occurrence of the
      * sequence contained in the str argument.
-     * \return SBuf::npos if the sequence  was not found
+     * \return npos if the sequence  was not found
      * \param endPos if specified, ignore any occurrences after that position
      *   if npos or greater than length(), the whole SBuf is considered
      *   if < 0, npos is always returned
@@ -508,9 +502,9 @@ public:
      *
      * Finds the first occurrence of ANY of the characters in the supplied set in
      * the SBuf.
-     * \return SBuf::npos if no character in the set could be found
+     * \return npos if no character in the set could be found
      * \param startPos if specified, ignore any occurrences before that position
-     *   if SBuf::npos, then npos is always returned
+     *   if npos, then npos is always returned
      *   if <0, it is ignored.
      */
     size_type find_first_of(const SBuf &set, size_type startPos = 0) const;
@@ -543,6 +537,9 @@ public:
      */
     String toString() const;
 
+    /// std::string export function
+    std::string toStdString() const { return std::string(buf(),length()); }
+
     // TODO: possibly implement erase() similar to std::string's erase
     // TODO: possibly implement a replace() call
 private:
@@ -552,7 +549,9 @@ private:
     size_type len_; ///< number of our content bytes in shared store_
     static SBufStats stats; ///< class-wide statistics
 
-    const InstanceId<SBuf> id; ///< blob identifier
+    /// SBuf object identifier; does not change when contents do,
+    ///   including during assignment
+    const InstanceId<SBuf> id;
 
     /** obtain prototype store
      *
@@ -582,44 +581,18 @@ private:
 
     void reAlloc(size_type newsize);
 
-    /**
-     * copy-on-write: make sure that we are the only holder of the backing store.
-     * If not, reallocate. If a new size is specified, and it is greater than the
-     * current length, the backing store will be extended as needed
-     * \retval false no grow was needed
-     * \retval true had to copy
-     */
-    bool cow(size_type minsize = npos) {
-        debugs(24, DBG_DATA, "new size (minimum):" << minsize);
-        if (minsize == npos || minsize < length())
-            minsize = length();
-
-        if (store_->LockCount() == 1 && minsize == length()) {
-            debugs(24, DBG_DATA, "no cow needed");
-            ++stats.cowFast;
-            return false;
-        }
-        reAlloc(minsize);
-        return true;
-    }
+    bool cow(size_type minsize = npos);
 
     void checkAccessBounds(size_type pos) const;
 
-    /**
-     * To be called after having determined that the buffers are equal up to the
-     * length of the shortest one.
-     * If the buffers' length is the same, then they're equal. Otherwise, the
-     * longest one is deemed to be greater than the other.
-     * This matches the behavior of strcmp(1) and strcasecmp(1)
-     */
-    int commonCompareChecksPost(const SBuf &S) const {
-        if (length() == S.length())
-            return 0;
-        if (length() > S.length())
-            return 1;
-        return -1;
-    }
-
+    /** Low-level append operation
+     *
+     * Takes as input a contiguous area of memory and appends its contents
+     * to the SBuf, taking care of memory management. Does no bounds checking
+     * on the supplied memory buffer, it is the duty of the caller to ensure
+     * that the supplied area is valid.
+     */
+    SBuf& lowAppend(const char * memArea, size_type areaSize);
 };
 
 /// ostream output operator
index 6378912764ea4a0ab898848faaf0e253a44397d3..63331f130e68fe846bcfa49f99d949a4a27cf1b6 100644 (file)
@@ -68,7 +68,7 @@ protected:
             char chars[1] = {static_cast<char>(aChar)};
 
             if (aChar != traits_type::eof())
-                theBuf.append(chars, 0, 1);
+                theBuf.append(chars, 1);
         }
 
         pbump(-pending);  // Reset pptr().
@@ -80,7 +80,7 @@ protected:
         std::streamsize pending(pptr() - pbase());
 
         if (pending)
-            theBuf.append(pbase(), 0, pending);
+            theBuf.append(pbase(), pending);
 
         return 0;
     }
@@ -90,7 +90,7 @@ protected:
      */
     virtual std::streamsize xsputn(const char * chars, std::streamsize number) {
         if (number)
-            theBuf.append(chars, 0, number);
+            theBuf.append(chars, number);
 
         return number;
     }
index 84e8ffe4ec99aeb7a05242ba8effc5f38f350a42..cd3d2079fcfa11f2562e3aa17cd4b9534be4a885 100644 (file)
@@ -380,7 +380,7 @@ SBufFindTest::RandomSBuf(const int length)
         buf[i] = characters[random() % charCount];
     }
 
-    return SBuf(buf, 0, length);
+    return SBuf(buf, length);
 }
 
 /// increments len to quickly cover [0, max] range, slowing down in risky areas
index a70534c68abae67b03665940644673dfe4157f7d..41cc334a3b2e045429207876cf8a8f451140e9f7 100644 (file)
@@ -48,49 +48,42 @@ testSBuf::testSBufConstructDestruct()
     //  test accessors on empty SBuf.
     {
         SBuf s1;
-        CPPUNIT_ASSERT_EQUAL(s1.length(),0);
-        CPPUNIT_ASSERT_EQUAL(s1,SBuf(""));
-        CPPUNIT_ASSERT_EQUAL(s1,empty_sbuf);
-        CPPUNIT_ASSERT(0==strcmp("",s1.c_str()));
+        CPPUNIT_ASSERT_EQUAL(0,s1.length());
+        CPPUNIT_ASSERT_EQUAL(SBuf(""),s1);
+        CPPUNIT_ASSERT_EQUAL(empty_sbuf,s1);
+        CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1.c_str()));
     }
 
     // TEST: copy-construct NULL string (implicit destructor non-crash test)
     {
         SBuf s1(NULL);
-        CPPUNIT_ASSERT_EQUAL(s1.length(),0);
-        CPPUNIT_ASSERT_EQUAL(s1,SBuf(""));
-        CPPUNIT_ASSERT_EQUAL(s1,empty_sbuf);
-        CPPUNIT_ASSERT(0==strcmp("",s1.c_str()));
+        CPPUNIT_ASSERT_EQUAL(0,s1.length());
+        CPPUNIT_ASSERT_EQUAL(SBuf(""),s1);
+        CPPUNIT_ASSERT_EQUAL(empty_sbuf,s1);
+        CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1.c_str()));
     }
 
     // TEST: copy-construct empty string (implicit destructor non-crash test)
     {
         SBuf s1("");
-        CPPUNIT_ASSERT_EQUAL(s1.length(),0);
-        CPPUNIT_ASSERT_EQUAL(s1,SBuf(""));
-        CPPUNIT_ASSERT_EQUAL(s1,empty_sbuf);
-        CPPUNIT_ASSERT(0==strcmp("",s1.c_str()));
-    }
-
-    // TEST: copy-construct from a char*
-    {
-        SBuf s1(fox);
-        CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(s1.length()),strlen(fox));
-        CPPUNIT_ASSERT(0==strcmp(fox,s1.c_str()));
+        CPPUNIT_ASSERT_EQUAL(0,s1.length());
+        CPPUNIT_ASSERT_EQUAL(SBuf(""),s1);
+        CPPUNIT_ASSERT_EQUAL(empty_sbuf,s1);
+        CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1.c_str()));
     }
 
     // TEST: copy-construct from a SBuf
     {
         SBuf s1(empty_sbuf);
-        CPPUNIT_ASSERT_EQUAL(s1.length(),0);
-        CPPUNIT_ASSERT_EQUAL(s1,SBuf(""));
-        CPPUNIT_ASSERT_EQUAL(s1,empty_sbuf);
-        CPPUNIT_ASSERT(0==strcmp("",s1.c_str()));
+        CPPUNIT_ASSERT_EQUAL(0,s1.length());
+        CPPUNIT_ASSERT_EQUAL(SBuf(""),s1);
+        CPPUNIT_ASSERT_EQUAL(empty_sbuf,s1);
+        CPPUNIT_ASSERT_EQUAL(0,strcmp("",s1.c_str()));
 
         SBuf s5(literal);
-        CPPUNIT_ASSERT_EQUAL(s5,literal);
+        CPPUNIT_ASSERT_EQUAL(literal,s5);
         SBuf s6(fox);
-        CPPUNIT_ASSERT_EQUAL(s6,literal);
+        CPPUNIT_ASSERT_EQUAL(literal,s6);
         // XXX: other state checks. expected result of calling any state accessor on s4 ?
     }
 
@@ -104,10 +97,10 @@ testSBuf::testSBufConstructDestruct()
 
     // TEST: sub-string copy
     {
-        SBuf s1=SBuf(fox,4), s2(fox);
+        SBuf s1=SBuf(fox+4), s2(fox);
         SBuf s3=s2.substr(4,s2.length()); //n is out-of-bounds
         CPPUNIT_ASSERT_EQUAL(s1,s3);
-        SBuf s4=SBuf(fox,0,4);
+        SBuf s4=SBuf(fox,4);
         s3=s2.substr(0,4);
         CPPUNIT_ASSERT_EQUAL(s4,s3);
     }
@@ -116,16 +109,15 @@ testSBuf::testSBufConstructDestruct()
     {
         String str(fox);
         SBuf s1(str);
-        CPPUNIT_ASSERT_EQUAL(s1,literal);
+        CPPUNIT_ASSERT_EQUAL(literal,s1);
     }
 
     // TEST: go via std::string adapter.
     {
         std::string str(fox);
         SBuf s1(str);
-        CPPUNIT_ASSERT_EQUAL(s1,literal);
+        CPPUNIT_ASSERT_EQUAL(literal,s1);
     }
-
 }
 
 void
@@ -133,7 +125,6 @@ testSBuf::testSBufConstructDestructAfterMemInit()
 {
     Mem::Init();
     testSBufConstructDestruct();
-
 }
 
 void
@@ -182,10 +173,26 @@ testSBuf::testAppendCString()
 void
 testSBuf::testAppendStdString()
 {
-    SBuf s1(fox1);
-    std::string str(fox2);
-    s1.append(str);
-    CPPUNIT_ASSERT_EQUAL(s1,literal);
+    const char *alphabet="abcdefghijklmnopqrstuvwxyz";
+    {
+        SBuf alpha(alphabet), s;
+        s.append(alphabet,5).append(alphabet+5);
+        CPPUNIT_ASSERT_EQUAL(alpha,s);
+    }
+    {
+        SBuf s;
+        std::string control;
+        s.append(alphabet,5).append("\0",1).append(alphabet+6,SBuf::npos);
+        control.append(alphabet,5).append(1,'\0').append(alphabet,6,std::string::npos);
+        SBuf scontrol(control); // we need this to test the equality. sigh.
+        CPPUNIT_ASSERT_EQUAL(scontrol,s);
+    }
+    {
+        const char *alphazero="abcdefghijk\0mnopqrstuvwxyz";
+        SBuf s(alphazero,26);
+        std::string str(alphazero,26);
+        CPPUNIT_ASSERT_EQUAL(0,memcmp(str.data(),s.rawContent(),26));
+    }
 }
 
 void
@@ -241,17 +248,35 @@ testSBuf::testComparisons()
 {
     //same length
     SBuf s1("foo"),s2("foe");
-    CPPUNIT_ASSERT(s1.compare(s2)>0);
-    CPPUNIT_ASSERT(s1.compare(s2,caseInsensitive,2)==0);
+    CPPUNIT_ASSERT(s1.cmp(s2)>0);
+    CPPUNIT_ASSERT(s1.caseCmp(s2)>0);
+    CPPUNIT_ASSERT(s2.cmp(s1)<0);
+    CPPUNIT_ASSERT_EQUAL(0,s1.cmp(s2,2));
+    CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2,2));
     CPPUNIT_ASSERT(s1 > s2);
     CPPUNIT_ASSERT(s2 < s1);
-    CPPUNIT_ASSERT_EQUAL(sign(s1.compare(s2)),sign(strcmp(s1.c_str(),s2.c_str())));
+    CPPUNIT_ASSERT_EQUAL(sign(s1.cmp(s2)),sign(strcmp(s1.c_str(),s2.c_str())));
     //different lengths
     s1.assign("foo");
     s2.assign("foof");
-    CPPUNIT_ASSERT(s1.compare(s2)<0);
-    CPPUNIT_ASSERT_EQUAL(sign(s1.compare(s2)),sign(strcmp(s1.c_str(),s2.c_str())));
+    CPPUNIT_ASSERT(s1.cmp(s2)<0);
+    CPPUNIT_ASSERT_EQUAL(sign(s1.cmp(s2)),sign(strcmp(s1.c_str(),s2.c_str())));
     CPPUNIT_ASSERT(s1 < s2);
+    // specifying the max-length and overhanging size
+    CPPUNIT_ASSERT_EQUAL(1,SBuf("foolong").caseCmp(SBuf("foo"), 5));
+    // case-insensive comaprison
+    s1 = "foo";
+    s2 = "fOo";
+    CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2));
+    CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2,2));
+    // \0-clenliness test
+    s1.assign("f\0oo",4);
+    s2.assign("f\0Oo",4);
+    CPPUNIT_ASSERT_EQUAL(1,s1.cmp(s2));
+    CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2));
+    CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2,3));
+    CPPUNIT_ASSERT_EQUAL(0,s1.caseCmp(s2,2));
+    CPPUNIT_ASSERT_EQUAL(0,s1.cmp(s2,2));
 }
 
 void
@@ -275,7 +300,7 @@ testSBuf::testRawContent()
     s2.append("foo");
     const char *foo;
     foo = s1.rawContent();
-    CPPUNIT_ASSERT(strncmp(fox,foo,s1.length())==0);
+    CPPUNIT_ASSERT_EQUAL(0,strncmp(fox,foo,s1.length()));
     foo = s1.c_str();
     CPPUNIT_ASSERT(!strcmp(fox,foo));
 }
@@ -416,8 +441,8 @@ testSBuf::testFindChar()
     // FORWARD SEARCH
     // needle in haystack
     idx=s1.find('d');
-    CPPUNIT_ASSERT(idx == 3);
-    CPPUNIT_ASSERT(s1[idx]=='d');
+    CPPUNIT_ASSERT_EQUAL(3,idx);
+    CPPUNIT_ASSERT_EQUAL('d',s1[idx]);
 
     // needle not present in haystack
     idx=s1.find(' '); //fails
@@ -610,18 +635,18 @@ testSBuf::testRFindSBuf()
 
     // corner case: search for a needle longer than the haystack
     idx=afox.rfind(SBuf("     "));
-    CPPUNIT_ASSERT(idx==SBuf::npos);
+    CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
 
     idx=haystack.rfind(SBuf("fox"));
     CPPUNIT_ASSERT_EQUAL(16,idx);
 
     // needle not found, no match for first char
     idx=goobar.rfind(SBuf("foo"));
-    CPPUNIT_ASSERT(idx==SBuf::npos);
+    CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
 
     // needle not found, match for first char but no match for SBuf
     idx=haystack.rfind(SBuf("foe"));
-    CPPUNIT_ASSERT(idx==SBuf::npos);
+    CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
 
     SBuf g("g"); //match at the last char
     idx=haystack.rfind(g);
@@ -639,14 +664,14 @@ testSBuf::testRFindSBuf()
     haystack="The quick brown fox";
     SBuf needle("foxy lady");
     idx=haystack.rfind(needle);
-    CPPUNIT_ASSERT(idx==SBuf::npos);
+    CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
 }
 
 void
 testSBuf::testSBufLength()
 {
     SBuf s(fox);
-    CPPUNIT_ASSERT((size_t)s.length()==strlen(fox));
+    CPPUNIT_ASSERT_EQUAL(strlen(fox),(size_t)s.length());
 }
 
 void
@@ -659,33 +684,36 @@ testSBuf::testScanf()
     int rv;
     s1.assign("string , 123 , 123.50");
     rv=s1.scanf("%s , %d , %f",s,&i,&f);
-    CPPUNIT_ASSERT(3 == rv);
-    CPPUNIT_ASSERT(0 == strcmp(s,"string"));
-    CPPUNIT_ASSERT(i == 123);
-    CPPUNIT_ASSERT(f == 123.5);
+    CPPUNIT_ASSERT_EQUAL(3,rv);
+    CPPUNIT_ASSERT_EQUAL(0,strcmp(s,"string"));
+    CPPUNIT_ASSERT_EQUAL(123,i);
+    CPPUNIT_ASSERT_EQUAL(static_cast<float>(123.5),f);
 }
 
 void testSBuf::testCopy()
 {
     char buf[40]; //shorter than literal()
     SBuf s(fox1),s2;
-    CPPUNIT_ASSERT(s.copy(buf,40)==s.length());
-    CPPUNIT_ASSERT(strncmp(s.rawContent(),buf,s.length())==0);
+    CPPUNIT_ASSERT_EQUAL(s.length(),s.copy(buf,40));
+    CPPUNIT_ASSERT_EQUAL(0,strncmp(s.rawContent(),buf,s.length()));
     s=literal;
-    CPPUNIT_ASSERT(s.copy(buf,40)==40);
-    s2.assign(buf,0,40);
+    CPPUNIT_ASSERT_EQUAL(40,s.copy(buf,40));
+    s2.assign(buf,40);
     s.chop(0,40);
-    CPPUNIT_ASSERT(s==s2);
+    CPPUNIT_ASSERT_EQUAL(s2,s);
 }
 
 void testSBuf::testStringOps()
 {
-    SBuf sng(literal),
+    SBuf sng(literal.toLower()),
     ref("the quick brown fox jumped over the lazy dog");
-    sng=sng.toLower();
     CPPUNIT_ASSERT_EQUAL(ref,sng);
     sng=literal;
-    CPPUNIT_ASSERT(0==sng.compare(ref,caseInsensitive));
+    CPPUNIT_ASSERT_EQUAL(0,sng.compare(ref,caseInsensitive));
+    // max-size comparison
+    CPPUNIT_ASSERT_EQUAL(0,ref.compare(SBuf("THE"),caseInsensitive,3));
+    CPPUNIT_ASSERT_EQUAL(1,ref.compare(SBuf("THE"),caseInsensitive,6));
+    CPPUNIT_ASSERT_EQUAL(0,SBuf("the").compare(SBuf("THE"),caseInsensitive,6));
 }
 
 void testSBuf::testGrow()
@@ -699,7 +727,7 @@ void testSBuf::testGrow()
     ref=match;
     t.append(literal).append(literal).append(literal).append(literal).append(literal);
     t.append(t).append(t).append(t).append(t).append(t);
-    CPPUNIT_ASSERT(match==ref);
+    CPPUNIT_ASSERT_EQUAL(ref,match);
 }
 
 void testSBuf::testStartsWith()
@@ -707,14 +735,15 @@ void testSBuf::testStartsWith()
     static SBuf casebuf("THE QUICK");
     CPPUNIT_ASSERT(literal.startsWith(SBuf(fox1)));
     CPPUNIT_ASSERT(!SBuf("The quick brown").startsWith(SBuf(fox1))); //too short
-    CPPUNIT_ASSERT(!literal.startsWith(SBuf(fox2))); //wrong contents
+    CPPUNIT_ASSERT(!literal.startsWith(SBuf(fox2))); //different contents
 
+    // case-insensitive checks
     CPPUNIT_ASSERT(literal.startsWith(casebuf,caseInsensitive));
     casebuf=SBuf(fox1).toUpper();
     CPPUNIT_ASSERT(literal.startsWith(casebuf,caseInsensitive));
     CPPUNIT_ASSERT(literal.startsWith(SBuf(fox1),caseInsensitive));
     casebuf = "tha quick";
-    CPPUNIT_ASSERT(!literal.startsWith(casebuf,caseInsensitive));
+    CPPUNIT_ASSERT_EQUAL(false,literal.startsWith(casebuf,caseInsensitive));
 }
 
 void testSBuf::testSBufStream()
@@ -741,7 +770,7 @@ void testSBuf::testFindFirstOf()
 
     // not found
     idx=haystack.find_first_of(SBuf("ADHRWYP"));
-    CPPUNIT_ASSERT(idx==SBuf::npos);
+    CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx);
 
     // found at beginning
     idx=haystack.find_first_of(SBuf("THANDF"));
@@ -761,3 +790,11 @@ void testSBuf::testAutoFind()
     SBufFindTest test;
     test.run();
 }
+
+void testSBuf::testStdStringOps()
+{
+    const char *alphabet="abcdefghijklmnopqrstuvwxyz";
+    std::string astr(alphabet);
+    SBuf sb(alphabet);
+    CPPUNIT_ASSERT_EQUAL(astr,sb.toStdString());
+}
index 241889f219c723f9a12b8cddb83cc3bb1b2d0e4e..373eeef1185de06c27cb47bdd5f7a37697d00830 100644 (file)
@@ -42,6 +42,7 @@ class testSBuf : public CPPUNIT_NS::TestFixture
     CPPUNIT_TEST( testGrow );
     CPPUNIT_TEST( testSBufStream );
     CPPUNIT_TEST( testAutoFind );
+    CPPUNIT_TEST( testStdStringOps );
 //    CPPUNIT_TEST( testDumpStats ); //fake test, to print alloc stats
     CPPUNIT_TEST_SUITE_END();
 protected:
@@ -79,6 +80,7 @@ protected:
     void testSBufStream();
     void testFindFirstOf();
     void testAutoFind();
+    void testStdStringOps();
 };
 
 #endif