On Fri, Nov 29, 2013 at 2:26 AM, Alex Rousskov <rouss...@measurement-factory.com> wrote: > On 11/26/2013 02:28 AM, Kinkie wrote: > >> +bool isMember(const SBufList &, const SBuf &, SBufCaseSensitive >> isCaseSensitive = caseSensitive); > > Please capitalize global names, such as isMember().
Ok >> +bool >> +isMember(const SBufList & sl, const SBuf &S, SBufCaseSensitive >> case_sensitive) >> +{ >> + for (SBufList::const_iterator i = sl.begin(); i != sl.end(); ++i) >> + if (i->compare(S,case_sensitive) == 0) >> + return true; >> + return false; >> +} > > STL already provides std::find() and std::find_if() that are more > flexible/universal and sometimes faster than isMember(). I suggest that > you provide a predicate to be used for case-specific comparisons of > buffers instead of isMember(). Such a predicate would be usable with any > SBuf container, not just SBufList. I suspect that these better belong to SBuf.cc than to SBufList.cc then. Done so, and with perfect feature creep made it parametric (case sensitive/insensitive) and built one also for prefix match. Do you agree these two small auxiliary classes belong to SBuf.h or do you think they should go elsewhere? >> +SBuf >> +SBufListJoin(const SBufList &list, const SBuf &separator) >> +{ >> + if (list.size() == 0) >> + return SBuf(""); >> + if (list.size() == 1) >> + return list.front(); > > This may be very ineffient for large lists and is probably unnecessary. > Avoid list.size() calls if it all possible. std::list::size() is O(n), > not O(1) in some older GCC implementations (at least). For one heated > discussion, see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49561 > > > >> + SBufList::const_iterator i; >> + // calculate the total size of the return value >> + SBuf::size_type sz = 0; >> + for (i = list.begin(); i != list.end(); ++i) >> + sz += i->length(); >> + sz += separator.length()*list.size(); >> + >> + SBuf rv; >> + rv.rawSpace(sz); >> + >> + i = list.begin(); >> + rv.append(*i); >> + ++i; >> + for (; i!= list.end(); ++i) { >> + rv.append(separator); >> + rv.append(*i); >> + } >> + return rv; >> +} > > > Consider using std::accumulate with an appropriate operator instead of > the above. Providing such an operator would allow folks to "join" SBufs > stored in any SBUf container, not just SBufList. Size precalculation is an optimization. I've made use of std:accumulate via SBufListAccumulateSizes, but I'm not sure it'd be worthwile to make that available throughout the code base. If so, would SBuf.h be a good place? >>>> attached is v1 of SBufList. Its purpose is to be the eventual heir >>>> to wordlist. > > > It may be useful to take a step back and decide whether we need a > one-size-fits all wordlist or many SBuf containers, with different > storage/access trade-offs. I am pretty sure it is the latter. The above > suggestions are meant to make your work usable with all containers (and > minimize code duplication). I'd like to avoid scope creep. This code is meant to supersede wordlist and bring the huge amount of code that uses it into the c++ world (and into the world of managed memory), and it can certainly be a step towards that end goal . SBuf should be reasonably container-friendly and can certainly be made even more so, but I'd prefer to address things as the need arises instead of overdesigning them. I'm attaching the revised patch. -- /kinkie
=== modified file 'src/SBuf.h' --- src/SBuf.h 2013-10-08 04:17:17 +0000 +++ src/SBuf.h 2013-11-29 15:16:09 +0000 @@ -607,4 +607,31 @@ return S.print(os); } +/** SBuf comparison predicate + * + * Comparison predicate for standard library containers. + */ +class SBufComparePredicate { +public: + explicit SBufComparePredicate(const SBuf s, SBufCaseSensitive caseSensitive = caseSensitive) : + compareWith(s), sensitive(caseSensitive) {} + inline bool operator() (const SBuf & checking) { return 0 == checking.compare(compareWith,sensitive); } +private: + SBuf compareWith; + SBufCaseSensitive sensitive; + SBufComparePredicate(); //no default constructor +}; + +class SBufPrefixComparePredicate { +public: + explicit SBufPrefixComparePredicate(const SBuf s, SBufCaseSensitive caseSensitive = caseSensitive) : + compareWith(s), sensitive(caseSensitive) {} + inline bool operator() (const SBuf & checking) { return 0 == checking.startsWith(compareWith,sensitive); } +private: + SBuf compareWith; + SBufCaseSensitive sensitive; + SBufPrefixComparePredicate(); //no default constructor +}; + + #endif /* SQUID_SBUF_H */ === added file 'src/SBufList.cc' --- src/SBufList.cc 1970-01-01 00:00:00 +0000 +++ src/SBufList.cc 2013-12-01 21:37:19 +0000 @@ -0,0 +1,55 @@ +#include "squid.h" +#include "SBufList.h" +#include "wordlist.h" + +#include <algorithm> + +bool +IsMember(const SBufList & sl, const SBuf &S, SBufCaseSensitive case_sensitive) +{ + return sl.end() != std::find_if(sl.begin(), sl.end(), + SBufComparePredicate(S,case_sensitive)); +} + +static inline SBuf::size_type +SBufListAccumulateSizes(SBuf::size_type sz, const SBuf &item) +{ + return sz + item.length(); +} + +SBuf +SBufListJoin(const SBufList &list, const SBuf &separator) +{ + // optimization: on empty list, return empty SBuf + if (list.begin() == list.end()) //empty + return SBuf(""); + + // optimization: pre-calculate needed storage + SBuf::size_type sz = 0; + std::accumulate(list.begin(), list.end(), sz, SBufListAccumulateSizes); + sz += separator.length() * list.size(); + + SBuf rv; + rv.rawSpace(sz); + + // + SBufList::const_iterator i = list.begin(); + rv.append(*i); + ++i; + for (; i!= list.end(); ++i) { + rv.append(separator); + rv.append(*i); + } + return rv; +} + +SBufList +wordlistToSBufList(wordlist *wl) +{ + SBufList rv; + while (wl != NULL) { + rv.push_back(SBuf(wl->key)); + wl = wl->next; + } + return rv; +} === added file 'src/SBufList.h' --- src/SBufList.h 1970-01-01 00:00:00 +0000 +++ src/SBufList.h 2013-12-01 21:37:19 +0000 @@ -0,0 +1,26 @@ +#ifndef SQUID_SBUFLIST_H +#define SQUID_SBUFLIST_H + +#include "SBuf.h" + +#include <list> + +typedef std::list<SBuf> SBufList; + +/** check for membership + * + * \return true if the supplied SBuf is a member of the list + * \param case_sensitive one of caseSensitive or caseInsensitive + */ +bool IsMember(const SBufList &, const SBuf &, SBufCaseSensitive isCaseSensitive = caseSensitive); + +/** join a SBufList into a SBuf using the supplied separator. + */ +SBuf SBufListJoin(const SBufList &list, const SBuf &separator = SBuf("")); + +class wordlist; +/** convert a wordlist to a SBufList + */ +SBufList wordlistToSbufList(wordlist *); + +#endif /* SQUID_SBUFLIST_H */ === added file 'src/tests/testSBufList.cc' --- src/tests/testSBufList.cc 1970-01-01 00:00:00 +0000 +++ src/tests/testSBufList.cc 2013-12-01 21:37:19 +0000 @@ -0,0 +1,36 @@ +#include "squid.h" +#include "SBufList.h" +#include "testSBufList.h" + +CPPUNIT_TEST_SUITE_REGISTRATION( testSBufList ); + +SBuf literal("The quick brown fox jumped over the lazy dog"); +static int sbuf_tokens_number=9; +static SBuf tokens[]={ + SBuf("The",3), SBuf("quick",5), SBuf("brown",5), SBuf("fox",3), + SBuf("jumped",6), SBuf("over",4), SBuf("the",3), SBuf("lazy",4), + SBuf("dog",3) +}; + +void +testSBufList::testSBufListMembership() +{ + SBufList foo; + for (int j=0; j<sbuf_tokens_number; ++j) + foo.push_back(tokens[j]); + CPPUNIT_ASSERT_EQUAL(true,IsMember(foo,SBuf("fox"))); + CPPUNIT_ASSERT_EQUAL(true,IsMember(foo,SBuf("Fox"),caseInsensitive)); + CPPUNIT_ASSERT_EQUAL(false,IsMember(foo,SBuf("garble"))); +} + +void +testSBufList::testSBufListJoin() +{ + SBufList foo; + CPPUNIT_ASSERT_EQUAL(SBuf(""),SBufListJoin(foo,SBuf(""))); + CPPUNIT_ASSERT_EQUAL(SBuf(""),SBufListJoin(foo)); + for (int j = 0; j < sbuf_tokens_number; ++j) + foo.push_back(tokens[j]); + SBuf joined=SBufListJoin(foo,SBuf(" ")); + CPPUNIT_ASSERT_EQUAL(literal,joined); +} === added file 'src/tests/testSBufList.h' --- src/tests/testSBufList.h 1970-01-01 00:00:00 +0000 +++ src/tests/testSBufList.h 2013-11-25 18:33:15 +0000 @@ -0,0 +1,19 @@ +#ifndef SQUID_SRC_TEST_TESTSBUF_H +#define SQUID_SRC_TEST_TESTSBUF_H + +#include <cppunit/extensions/HelperMacros.h> + +#include "OutOfBoundsException.h" + +class testSBufList : public CPPUNIT_NS::TestFixture +{ + CPPUNIT_TEST_SUITE( testSBufList ); + CPPUNIT_TEST( testSBufListMembership ); + CPPUNIT_TEST( testSBufListJoin ); + CPPUNIT_TEST_SUITE_END(); +protected: + void testSBufListMembership(); + void testSBufListJoin(); +}; + +#endif