OutOfBoundsException.h \
SBuf.h \
SBuf.cc \
- SBuf.cci \
SBufExceptions.h \
SBufExceptions.cc
}
SBuf::SBuf(const std::string &s)
- : store_(GetStorePrototype()), off_(0), len_(0)
+ : store_(GetStorePrototype()), off_(0), len_(0)
{
debugs(24, 8, id << " created from string");
assign(s.data(),0,s.size());
--stats.live;
}
+MemBlob::Pointer
+SBuf::GetStorePrototype()
+{
+ static MemBlob::Pointer InitialStore = NULL;
+ if (InitialStore == NULL) {
+ static char lowPrototype[] = "";
+ InitialStore = new MemBlob(lowPrototype, 0);
+ }
+ return InitialStore;
+}
+
SBuf&
SBuf::assign(const SBuf &S)
{
SBuf::startsWith(const SBuf &S, SBufCaseSensitive isCaseSensitive) const
{
debugs(24, 8, id << " startsWith " << S.id << ", caseSensitive: " <<
- isCaseSensitive);
+ isCaseSensitive);
if (length() < S.length()) {
debugs(24, 8, "no, too short");
++stats.compareFast;
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 <<
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;
++stats.cowSlow;
debugs(24, 7, "new store capacity: " << store_->capacity);
}
-
-#if !_USE_INLINE_
-#include "SBuf.cci"
-#endif
-
+++ /dev/null
-/*
- * SBuf.cc (C) 2008 Francesco Chemolli <kinkie@squid-cache.org>
- *
- * SQUID Web Proxy Cache http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- * Squid is the result of efforts by numerous individuals from
- * the Internet community; see the CONTRIBUTORS file for full
- * details. Many organizations have provided support for Squid's
- * development; see the SPONSORS file for full details. Squid is
- * Copyrighted (C) 2001 by the Regents of the University of
- * California; see the COPYRIGHT file for full details. Squid
- * incorporates software developed and/or copyrighted by other
- * sources; see the CREDITS file for full details.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- */
-
-#include "base/RefCount.h"
-#include "Debug.h"
-#include "OutOfBoundsException.h"
-#include "SBufExceptions.h"
-
-#if HAVE_CLIMITS
-#include <climits>
-#elif HAVE_LIMITS_H
-#include <limits.h>
-#endif
-
-SBuf&
-SBuf::operator =(const SBuf & S)
-{
- return assign(S);
-}
-
-SBuf&
-SBuf::operator =(const char *S)
-{
- return assign(S);
-}
-
-bool
-SBuf::operator <(const SBuf &S) const
-{
- return (compare(S) < 0);
-}
-
-bool
-SBuf::operator >(const SBuf &S) const
-{
- return (compare(S) > 0);
-}
-
-bool
-SBuf::operator <=(const SBuf &S) const
-{
- return (compare(S) <= 0);
-}
-
-bool
-SBuf::operator >=(const SBuf &S) const
-{
- return (compare(S) >= 0);
-}
-
-SBuf::size_type
-SBuf::length() const
-{
- return len_;
-}
-
-int
-SBuf::plength() const
-{
- if (length() > INT_MAX)
- throw SBufTooBigException(__FILE__, __LINE__);
- return (int)length();
-}
-
-/**
- * obtains a char* to the beginning of this SBuf in memory.
- * \note the obtained string is NOT null-terminated.
- */
-char *
-SBuf::buf() const
-{
- return store_->mem+off_;
-}
-
-/** returns the pointer to the first char after this SBuf end
- *
- * No checks are made that the space returned is safe, checking that is
- * up to the caller.
- */
-char *
-SBuf::bufEnd() const
-{
- return store_->mem+off_+len_;
-}
-
-/**
- * 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;
-}
-
-/**
- * Try to guesstimate how big a MemBlob to allocate.
- * The result is guarranteed to be to be at least the desired
- * size.
- */
-const SBuf::size_type
-SBuf::estimateCapacity(SBuf::size_type desired) const
-{
- return 2*desired;
-}
-
-/**
- * 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
-SBuf::commonCompareChecksPost(const SBuf &S) const
-{
- if (length() == S.length()) //I'll be damned..they're REALLY the same..
- return 0;
- if (length() > S.length())
- return 1;
- return -1;
-}
-
-/** obtain prototype store
- *
- * Just-created SBufs all share to the same MemBlob.
- * This call instantiates and returns it.
- */
-MemBlob::Pointer
-SBuf::GetStorePrototype()
-{
- static MemBlob::Pointer InitialStore = NULL;
- if (InitialStore == NULL) {
- static char lowPrototype[] = "";
- InitialStore = new MemBlob(lowPrototype, 0);
- }
- return InitialStore;
-}
-
-const char
-SBuf::operator [](SBuf::size_type pos) const
-{
- ++stats.getChar;
- return store_->mem[off_+pos];
-}
-
-const char
-SBuf::at(SBuf::size_type pos) const
-{
- checkAccessBounds(pos);
- return operator[](pos);
-}
-
-bool
-SBuf::isEmpty() const
-{
- return (len_ == 0);
-}
-
-std::ostream &
-operator <<(std::ostream& os, const SBuf& S)
-{
- return S.print(os);
-}
#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"
+#if HAVE_CLIMITS
+#include <climits>
+#elif HAVE_LIMITS_H
+#include <limits.h>
+#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
explicit SBuf(const std::string &s);
~SBuf();
+
/** Explicit assignment.
*
* Current SBuf will share backing store with the assigned one.
*/
SBuf& assign(const SBuf &S);
+
/** Assignment operator.
*
* Current SBuf will share backing store with the assigned one.
*/
- _SQUID_INLINE_ SBuf& operator =(const SBuf & S);
+ SBuf& operator =(const SBuf & S) {return assign(S);}
/** Import a c-string into a SBuf, copying the data.
*
* 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.
*/
- _SQUID_INLINE_ SBuf& operator =(const char *S);
+ SBuf& operator =(const char *S) {return assign(S);}
/** Import a std::string into a SBuf. Contents are copied.
*
*
* does not check access bounds. If you need that, use at()
*/
- _SQUID_INLINE_ const char operator [](size_type pos) const;
+ const char operator [](size_type pos) const {++stats.getChar; return store_->mem[off_+pos];}
/** random-access read to any char within the SBuf.
*
* \throw OutOfBoundsException when access is out of bounds
* \note bounds is 0 <= pos < length()
*/
- _SQUID_INLINE_ const char at(size_type pos) const;
+ const char at(size_type pos) const {checkAccessBounds(pos); return operator[](pos);}
/** direct-access set a byte at a specified operation.
*
bool operator ==(const SBuf & S) const;
bool operator !=(const SBuf & S) const;
- _SQUID_INLINE_ bool operator <(const SBuf &S) const;
- _SQUID_INLINE_ bool operator >(const SBuf &S) const;
- _SQUID_INLINE_ bool operator <=(const SBuf &S) const;
- _SQUID_INLINE_ 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);}
/** Consume bytes at the head of the SBuf
*
const char* c_str();
/// Returns the number of bytes stored in SBuf.
- _SQUID_INLINE_ size_type length() const;
+ size_type length() const {return len_;}
/** Get the length of the SBuf, as a signed integer
*
* Compatibility function for printf(3) which requires a signed int
* \throw SBufTooBigException if the SBuf is too big for a signed integer
*/
- _SQUID_INLINE_ int plength() const;
+ int plength() const {
+ if (length()>INT_MAX)
+ throw SBufTooBigException(__FILE__, __LINE__);
+ return static_cast<int>(length());
+ }
/** Check whether the SBuf is empty
*
* \return true if length() == 0
*/
- _SQUID_INLINE_ bool isEmpty() const;
+ bool isEmpty() const {return (len_==0);}
/** Request to extend the SBuf's free store space.
*
const InstanceId<SBuf> id; ///< blob identifier
- _SQUID_INLINE_ static MemBlob::Pointer GetStorePrototype();
+ /** obtain prototype store
+ *
+ * Just-created SBufs all share to the same MemBlob.
+ * This call instantiates and returns it.
+ */
+ static MemBlob::Pointer GetStorePrototype();
+
+ /**
+ * obtains a char* to the beginning of this SBuf in memory.
+ * \note the obtained string is NOT null-terminated.
+ */
+ char * buf() const {return (store_->mem+off_);}
+
+ /** returns the pointer to the first char after this SBuf end
+ *
+ * No checks are made that the space returned is safe, checking that is
+ * up to the caller.
+ */
+ char * bufEnd() const {return (store_->mem+off_+len_);}
+
+ /**
+ * Try to guesstimate how big a MemBlob to allocate.
+ * The result is guarranteed to be to be at least the desired size.
+ */
+ const size_type estimateCapacity(size_type desired) const {return (2*desired);}
- _SQUID_INLINE_ char * buf() const;
- _SQUID_INLINE_ char * bufEnd() const;
- _SQUID_INLINE_ const size_type estimateCapacity(size_type desired) const;
void reAlloc(size_type newsize);
- _SQUID_INLINE_ bool cow(size_type minsize = npos);
+ /**
+ * 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;
+ }
void checkAccessBounds(size_type pos) const;
_SQUID_INLINE_ int commonCompareChecksPre(const SBuf &S) const;
- _SQUID_INLINE_ int commonCompareChecksPost(const SBuf &S) 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;
+ }
};
/// ostream output operator
-_SQUID_INLINE_ std::ostream& operator <<(std::ostream &os, const SBuf &S);
-
-#if _USE_INLINE_
-#include "SBuf.cci"
-#endif
+inline std::ostream &
+operator <<(std::ostream& os, const SBuf& S)
+{
+ return S.print(os);
+}
#endif /* SQUID_SBUF_H */
SBuf::size_type &pos,
const char *aFileName, int aLineNo)
: TextException(NULL, aFileName, aLineNo),
- theThrowingBuf(throwingBuf),
- accessedPosition(pos)
+ theThrowingBuf(throwingBuf),
+ accessedPosition(pos)
{
SBuf explanatoryText("OutOfBoundsException");
if (aLineNo != -1)
if (aFileName != NULL)
explanatoryText.appendf(" in file %s", aFileName);
explanatoryText.appendf(" while accessing position %d in a SBuf long %d",
- pos, throwingBuf.length());
+ pos, throwingBuf.length());
// we can safely alias c_str as both are local to the object
// and will not further manipulated.
message = xstrndup(explanatoryText.c_str(),explanatoryText.length());
#include <cppunit/Message.h>
#include <limits>
-
/* TODO: The whole SBufFindTest class is currently implemented as a single
CppUnit test case (because we do not want to register and report every one
of the thousands of generated test cases). Is there a better way to
integrate with CppUnit?
*/
-
SBufFindTest::SBufFindTest():
- caseLimit(std::numeric_limits<int>::max()),
- errorLimit(std::numeric_limits<int>::max()),
- randomSeed(1),
- hushSimilar(true),
- maxHayLength(40),
- thePos(0),
- thePlacement(placeEof),
- theStringPos(0),
- theBareNeedlePos(0),
- caseCount(0),
- errorCount(0),
- reportCount(0)
+ caseLimit(std::numeric_limits<int>::max()),
+ errorLimit(std::numeric_limits<int>::max()),
+ randomSeed(1),
+ hushSimilar(true),
+ maxHayLength(40),
+ thePos(0),
+ thePlacement(placeEof),
+ theStringPos(0),
+ theBareNeedlePos(0),
+ caseCount(0),
+ errorCount(0),
+ reportCount(0)
{
}
placeNeedle(cleanHay);
const SBuf::size_type maxArg =
- max(theSBufHay.length(), theSBufNeedle.length()) + 10;
+ max(theSBufHay.length(), theSBufNeedle.length()) + 10;
for (thePos = 0; thePos <= maxArg; nextLen(thePos, maxArg))
testAllMethods();
/// tests SBuf::find(string needle)
void
-SBufFindTest::testFindDefs() {
+SBufFindTest::testFindDefs()
+{
theFindString = theBareNeedlePos = theStringHay.find(theStringNeedle);
theFindSBuf = theSBufHay.find(theSBufNeedle);
checkResults("find");
/// tests SBuf::rfind(string needle)
void
-SBufFindTest::testRFindDefs() {
+SBufFindTest::testRFindDefs()
+{
theFindString = theBareNeedlePos = theStringHay.rfind(theStringNeedle);
theFindSBuf = theSBufHay.rfind(theSBufNeedle);
checkResults("rfind");
/// tests SBuf::find(string needle, pos)
void
-SBufFindTest::testFind() {
+SBufFindTest::testFind()
+{
theFindString = theStringHay.find(theStringNeedle, thePos);
theBareNeedlePos = theStringHay.find(theStringNeedle);
theFindSBuf = theSBufHay.find(theSBufNeedle, thePos);
/// tests SBuf::find_first_of(string needle, pos)
void
-SBufFindTest::testFindFirstOf() {
+SBufFindTest::testFindFirstOf()
+{
theFindString = theStringHay.find_first_of(theStringNeedle, thePos);
theBareNeedlePos = theStringHay.find_first_of(theStringNeedle);
theFindSBuf = theSBufHay.find_first_of(theSBufNeedle, thePos);
checkResults("find_first_of");
}
-
/// tests SBuf::rfind(string needle, pos)
void
-SBufFindTest::testRFind() {
+SBufFindTest::testRFind()
+{
theFindString = theStringHay.rfind(theStringNeedle, thePos);
theBareNeedlePos = theStringHay.rfind(theStringNeedle);
theFindSBuf = theSBufHay.rfind(theSBufNeedle, thePos);
/// tests SBuf::find(char needle)
void
-SBufFindTest::testFindCharDefs() {
+SBufFindTest::testFindCharDefs()
+{
const char c = theStringNeedle[0];
theFindString = theBareNeedlePos = theStringHay.find(c);
theFindSBuf = theSBufHay.find(c);
/// tests SBuf::find(char needle, pos)
void
-SBufFindTest::testFindChar() {
+SBufFindTest::testFindChar()
+{
const char c = theStringNeedle[0];
theFindString = theStringHay.find(c, thePos);
theBareNeedlePos = theStringHay.find(c);
/// tests SBuf::rfind(char needle)
void
-SBufFindTest::testRFindCharDefs() {
+SBufFindTest::testRFindCharDefs()
+{
const char c = theStringNeedle[0];
theFindString = theBareNeedlePos = theStringHay.rfind(c);
theFindSBuf = theSBufHay.rfind(c);
/// tests SBuf::rfind(char needle, pos)
void
-SBufFindTest::testRFindChar() {
+SBufFindTest::testRFindChar()
+{
const char c = theStringNeedle[0];
theFindString = theStringHay.rfind(c, thePos);
theBareNeedlePos = theStringHay.rfind(c);
/// whether the last SBuf and std::string find() results are the same
bool
-SBufFindTest::resultsMatch() const {
+SBufFindTest::resultsMatch() const
+{
// this method is needed because SBuf and std::string use different
// size_types (and npos values); comparing the result values directly
// would lead to bugs
return true; // both npos
if (theFindSBuf < 0) // should not happen, treat as error
- return false;
+ return false;
// now safe to cast a non-negative SBuf result
return theFindString == static_cast<std::string::size_type>(theFindSBuf);
/// called at the end of test case to update state, detect and report failures
void
-SBufFindTest::checkResults(const char *method) {
+SBufFindTest::checkResults(const char *method)
+{
++caseCount;
if (!resultsMatch())
handleFailure(method);
/// tests each supported SBuf::*find() method using generated hay, needle, pos
void
-SBufFindTest::testAllMethods() {
+SBufFindTest::testAllMethods()
+{
theStringHay = std::string(theSBufHay.rawContent(), theSBufHay.length());
theStringNeedle = std::string(theSBufNeedle.rawContent(), theSBufNeedle.length());
theBareNeedlePos = std::string::npos;
/// called when a test case fails; counts and possibly reports the failure
void
-SBufFindTest::handleFailure(const char *method) {
+SBufFindTest::handleFailure(const char *method)
+{
// line break after "........." printed for previous tests
if (!errorCount)
std::cerr << std::endl;
if (errorCount > errorLimit) {
std::cerr << "Will stop generating SBuf test cases because the " <<
- "number of failed ones is over the limit: " << errorCount <<
- " (after " << caseCount << " test cases)" << std::endl;
+ "number of failed ones is over the limit: " << errorCount <<
+ " (after " << caseCount << " test cases)" << std::endl;
CPPUNIT_ASSERT(errorCount <= errorLimit);
/* NOTREACHED */
}
// format test case category; category allows us to hush failure reports
// for already seen categories with failed cases (to reduce output noise)
std::string category = "hay" + lengthKey(theStringHay) +
- "." + method + '(';
+ "." + method + '(';
if (theReportQuote == '"')
category += "needle" + lengthKey(theStringNeedle);
else
reportPos = ", " + reportPos;
std::cerr << "case" << caseCount << ": " <<
- "SBuf(\"" << theStringHay << "\")." << method <<
- "(" << theReportQuote << theReportNeedle << theReportQuote <<
- reportPos << ") returns " << PosToString(theFindSBuf) <<
- " instead of " << PosToString(theFindString) <<
- std::endl <<
- " std::string(\"" << theStringHay << "\")." << method <<
- "(" << theReportQuote << theReportNeedle << theReportQuote <<
- reportPos << ") returns " << PosToString(theFindString) <<
- std::endl <<
- " category: " << category << std::endl;
-
- ++reportCount;
+ "SBuf(\"" << theStringHay << "\")." << method <<
+ "(" << theReportQuote << theReportNeedle << theReportQuote <<
+ reportPos << ") returns " << PosToString(theFindSBuf) <<
+ " instead of " << PosToString(theFindString) <<
+ std::endl <<
+ " std::string(\"" << theStringHay << "\")." << method <<
+ "(" << theReportQuote << theReportNeedle << theReportQuote <<
+ reportPos << ") returns " << PosToString(theFindString) <<
+ std::endl <<
+ " category: " << category << std::endl;
+
+ ++reportCount;
}
/// generates a random string of the specified length
SBuf
-SBufFindTest::RandomSBuf(const int length) {
- static const char characters[] =
+SBufFindTest::RandomSBuf(const int length)
+{
+ static const char characters[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklomnpqrstuvwxyz";
// sizeof() counts the terminating zero at the end of characters
// TODO: add \0 character (needs reporting adjustments to print it as \0)
- static const size_t charCount = sizeof(characters)-1;
+ static const size_t charCount = sizeof(characters)-1;
char buf[length];
for (int i = 0; i < length; ++i) {
/// increments len to quickly cover [0, max] range, slowing down in risky areas
/// jumps to max+1 if caseLimit is reached
void
-SBufFindTest::nextLen(int &len, const int max) {
+SBufFindTest::nextLen(int &len, const int max)
+{
assert(len <= max);
if (caseCount >= caseLimit)
/// Places the needle into the hay using cleanHay as a starting point.
void
-SBufFindTest::placeNeedle(const SBuf &cleanHay) {
+SBufFindTest::placeNeedle(const SBuf &cleanHay)
+{
// For simplicity, we do not overwrite clean hay characters but use them as
// needle suffix and/or prefix. Should not matter since hay length varies?
// TODO: support two needles per hay (explicitly)
// TODO: better handle cases where clean hay already contains needle
- switch (thePlacement)
- {
+ switch (thePlacement) {
case placeBeginning:
theSBufHay.assign(theSBufNeedle).append(cleanHay);
break;
- case placeMiddle:
- {
+ case placeMiddle: {
const SBuf firstHalf = cleanHay.substr(0, cleanHay.length()/2);
const SBuf secondHalf = cleanHay.substr(cleanHay.length()/2);
theSBufHay.assign(firstHalf).append(theSBufNeedle).append(secondHalf);
/// whether to report only one failed test case per "category"
bool hushSimilar;
/// approximate maximum generated hay string length
- SBuf::size_type maxHayLength;
+ SBuf::size_type maxHayLength;
/// Supported algorithms for placing needle in the hay.
typedef enum { placeBeginning, placeMiddle, placeEnd, placeNowhere,
- placeEof } Placement; // placeLast marker must terminate
+ placeEof
+ } Placement; // placeLast marker must terminate
protected:
static SBuf RandomSBuf(const int length);
CPPUNIT_ASSERT_EQUAL(s1,literal);
}
-
}
void
{
SBuf fullString, sb;
std::string fullReference, str;
- public:
- void performEqualityTest()
- {
+public:
+ void performEqualityTest() {
SBuf ref(str);
CPPUNIT_ASSERT_EQUAL(ref,sb);
}
- SBufSubstrAutoTest() : fullString(fox), fullReference(fox)
- {
+ SBufSubstrAutoTest() : fullString(fox), fullReference(fox) {
for (int offset=fullString.length()-1; offset >= 0; --offset ) {
for (int length=fullString.length()-1-offset; length >= 0; --length) {
sb=fullString.substr(offset,length);
CPPUNIT_ASSERT_EQUAL(23,idx);
}
-
// REVERSE search
// needle in haystack
idx = haystack.rfind(SBuf("def"));