# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: kinkie@squid-cache.org-20131217172853-bd9mhuk14tqmaunz # target_branch: ../trunk # testament_sha1: a0f01e9f4dba9b1740a76f8a55b1848fd69897e7 # timestamp: 2013-12-17 18:29:03 +0100 # base_revision_id: squid3@treenet.co.nz-20131217091651-\ # oxujawxqsudye9eh # # Begin patch === modified file 'src/Makefile.am' --- src/Makefile.am 2013-12-12 09:41:39 +0000 +++ src/Makefile.am 2013-12-17 17:05:17 +0000 @@ -15,6 +15,7 @@ DnsLookupDetails.cc SBUF_SOURCE= \ + base/CharacterSet.h \ base/InstanceId.h \ MemBlob.h \ MemBlob.cc \ === modified file 'src/SBuf.cc' --- src/SBuf.cc 2013-11-27 15:52:03 +0000 +++ src/SBuf.cc 2013-12-17 10:19:44 +0000 @@ -27,6 +27,7 @@ */ #include "squid.h" +#include "base/CharacterSet.h" #include "base/RefCount.h" #include "Debug.h" #include "OutOfBoundsException.h" @@ -688,28 +689,45 @@ } SBuf::size_type -SBuf::find_first_of(const SBuf &set, size_type startPos) const -{ - // if set is 1 char big, use the char search. Stats updated there - if (set.length() == 1) - return find(set[0], startPos); - - ++stats.find; - - if (startPos == npos) - return npos; - - if (startPos >= length()) - return npos; - - if (set.length() == 0) - return npos; - - debugs(24, 7, "any of '" << set << "' " << " in id " << id); - char *cur = buf()+startPos, *end = bufEnd(); - while (cur < end) { - if (memchr(set.buf(), *cur, set.length())) - return (cur-buf()); +SBuf::find_first_of(const CharacterSet &set, size_type startPos) const +{ + ++stats.find; + + if (startPos == npos) + return npos; + + if (startPos >= length()) + return npos; + + debugs(24, 7, "first of characterset " << set.name << " in id " << id); + char *cur = buf()+startPos; + const char *end = bufEnd(); + while (cur < end) { + if (set[*cur]) + return cur-buf(); + ++cur; + } + debugs(24, 7, "not found"); + return npos; +} + +SBuf::size_type +SBuf::find_first_not_of(const CharacterSet &set, size_type startPos) const +{ + ++stats.find; + + if (startPos == npos) + return npos; + + if (startPos >= length()) + return npos; + + debugs(24, 7, "first not of characterset " << set.name << " in id " << id); + char *cur = buf()+startPos; + const char *end = bufEnd(); + while (cur < end) { + if (!set[*cur]) + return cur-buf(); ++cur; } debugs(24, 7, "not found"); === modified file 'src/SBuf.h' --- src/SBuf.h 2013-12-04 18:37:08 +0000 +++ src/SBuf.h 2013-12-17 10:19:44 +0000 @@ -101,6 +101,8 @@ SBufStats& operator +=(const SBufStats&); }; +class CharacterSet; + /** * A String or Buffer. * Features: refcounted backing store, cheap copy and sub-stringing @@ -512,8 +514,20 @@ * \return npos if no character in the set could be found * \param startPos if specified, ignore any occurrences before that position * if npos, then npos is always returned - */ - size_type find_first_of(const SBuf &set, size_type startPos = 0) const; + * + * TODO: rename to camelCase + */ + size_type find_first_of(const CharacterSet &set, size_type startPos = 0) const; + + /** Find first occurrence character NOT in character set + * + * \return npos if all characters in the SBuf are from set + * \param startPos if specified, ignore any occurrences before that position + * if npos, then npos is always returned + * + * TODO: rename to camelCase + */ + size_type find_first_not_of(const CharacterSet &set, size_type startPos = 0) const; /** sscanf-alike * === added file 'src/base/CharacterSet.cc' --- src/base/CharacterSet.cc 1970-01-01 00:00:00 +0000 +++ src/base/CharacterSet.cc 2013-12-17 17:02:51 +0000 @@ -0,0 +1,32 @@ +#include "squid.h" + +#include "CharacterSet.h" + +#include + +static bool +isNonZero(uint8_t i) { + return i!=0; +} + +const CharacterSet & +CharacterSet::operator +=(const CharacterSet &src) +{ + std::copy_if(src.chars_.begin(),src.chars_.end(),chars_.begin(),isNonZero); + return *this; +} + +CharacterSet & +CharacterSet::add(const unsigned char c) +{ + chars_[static_cast(c)] = 1; + return *this; +} + +CharacterSet::CharacterSet(const char *label, const char * const c) +: name(label == NULL ? "anonymous" : label), chars_(vector_type(256,0)) +{ + const size_t clen = strlen(c); + for (size_t i = 0; i < clen; ++i) + add(c[i]); +} === added file 'src/base/CharacterSet.h' --- src/base/CharacterSet.h 1970-01-01 00:00:00 +0000 +++ src/base/CharacterSet.h 2013-12-17 17:28:53 +0000 @@ -0,0 +1,38 @@ +#ifndef _SQUID_SRC_PARSER_CHARACTERSET_H +#define _SQUID_SRC_PARSER_CHARACTERSET_H + +#include + +/// Optimized set of C chars, with quick membership test and merge support +class CharacterSet +{ +public: + typedef std::vector vector_type; + + /// define a character set with the given label ("anonymous" if NULL, + /// with specified initial contents + CharacterSet(const char *label, const char * const initial); + + /// whether a given character exists in the set + bool operator[](unsigned char c) const {return chars_[static_cast(c)] == 1;} + + /// add a given character to the character set. + CharacterSet & add(const unsigned char c); + + /// add all characters from the given CharacterSet to this one + const CharacterSet &operator +=(const CharacterSet &src); + + /// optional set label for debugging (default: "anonymous") + const char * name; + +private: + /** characters present in this set. + * + * \note guaranteed to be always 256 slots big, as forced in the + * constructor. This assumption is relied upon in operator[], add, + * operator+= + */ + vector_type chars_; +}; + +#endif /* _SQUID_SRC_PARSER_CHARACTERSET_H */ === modified file 'src/base/Makefile.am' --- src/base/Makefile.am 2013-11-26 09:43:29 +0000 +++ src/base/Makefile.am 2013-12-17 10:19:44 +0000 @@ -12,6 +12,8 @@ AsyncJobCalls.h \ AsyncCallQueue.cc \ AsyncCallQueue.h \ + CharacterSet.h \ + CharacterSet.cc \ TidyPointer.h \ CbcPointer.h \ InstanceId.h \ === modified file 'src/icmp/Makefile.am' --- src/icmp/Makefile.am 2013-12-03 07:49:13 +0000 +++ src/icmp/Makefile.am 2013-12-15 11:47:07 +0000 @@ -23,6 +23,7 @@ noinst_LTLIBRARIES = libicmp-core.la libicmp.la SBUF_SOURCE= \ + $(top_srcdir)/src/base/CharacterSet.h \ $(top_srcdir)/src/SBuf.h \ $(top_srcdir)/src/SBuf.cc \ $(top_srcdir)/src/MemBlob.h \ === modified file 'src/tests/SBufFindTest.cc' --- src/tests/SBufFindTest.cc 2013-11-11 12:06:11 +0000 +++ src/tests/SBufFindTest.cc 2013-12-15 12:48:01 +0000 @@ -1,4 +1,5 @@ #include "squid.h" +#include "base/CharacterSet.h" #include "SBufFindTest.h" #include #include @@ -105,7 +106,7 @@ { theFindString = theStringHay.find_first_of(theStringNeedle, thePos); theBareNeedlePos = theStringHay.find_first_of(theStringNeedle); - theFindSBuf = theSBufHay.find_first_of(theSBufNeedle, thePos); + theFindSBuf = theSBufHay.find_first_of(CharacterSet("cs",theSBufNeedle.c_str()), thePos); checkResults("find_first_of"); } === modified file 'src/tests/testSBuf.cc' --- src/tests/testSBuf.cc 2013-11-27 15:52:03 +0000 +++ src/tests/testSBuf.cc 2013-12-17 10:19:44 +0000 @@ -1,4 +1,5 @@ #include "squid.h" +#include "base/CharacterSet.h" #include "Mem.h" #include "SBuf.h" #include "SBufFindTest.h" @@ -759,23 +760,47 @@ SBuf::size_type idx; // not found - idx=haystack.find_first_of(SBuf("ADHRWYP")); + idx=haystack.find_first_of(CharacterSet("t1","ADHRWYP")); CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx); // found at beginning - idx=haystack.find_first_of(SBuf("THANDF")); + idx=haystack.find_first_of(CharacterSet("t2","THANDF")); CPPUNIT_ASSERT_EQUAL(0U,idx); //found at end of haystack - idx=haystack.find_first_of(SBuf("QWERYVg")); + idx=haystack.find_first_of(CharacterSet("t3","QWERYVg")); CPPUNIT_ASSERT_EQUAL(haystack.length()-1,idx); //found in the middle of haystack - idx=haystack.find_first_of(SBuf("QWERqYV")); + idx=haystack.find_first_of(CharacterSet("t4","QWERqYV")); CPPUNIT_ASSERT_EQUAL(4U,idx); } void +testSBuf::testFindFirstNotOf() +{ + SBuf haystack(literal); + SBuf::size_type idx; + + // all chars from the set + idx=haystack.find_first_not_of(CharacterSet("t1",literal.c_str())); + CPPUNIT_ASSERT_EQUAL(SBuf::npos,idx); + + // found at beginning + idx=haystack.find_first_not_of(CharacterSet("t2","a")); + CPPUNIT_ASSERT_EQUAL(0U,idx); + + //found at end of haystack + idx=haystack.find_first_not_of(CharacterSet("t3",literal.substr(0,literal.length()-1).c_str())); + CPPUNIT_ASSERT_EQUAL(haystack.length()-1,idx); + + //found in the middle of haystack + idx=haystack.find_first_not_of(CharacterSet("t4","The")); + CPPUNIT_ASSERT_EQUAL(3U,idx); +} + + +void testSBuf::testAutoFind() { SBufFindTest test; === modified file 'src/tests/testSBuf.h' --- src/tests/testSBuf.h 2013-07-26 09:20:09 +0000 +++ src/tests/testSBuf.h 2013-12-15 11:47:07 +0000 @@ -35,6 +35,7 @@ CPPUNIT_TEST( testRFindChar ); CPPUNIT_TEST( testRFindSBuf ); CPPUNIT_TEST( testFindFirstOf ); + CPPUNIT_TEST( testFindFirstNotOf ); CPPUNIT_TEST( testPrintf ); CPPUNIT_TEST( testScanf ); CPPUNIT_TEST( testCopy ); @@ -79,6 +80,7 @@ void testStartsWith(); void testSBufStream(); void testFindFirstOf(); + void testFindFirstNotOf(); void testAutoFind(); void testStdStringOps(); }; # Begin bundle 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