On Mon, Dec 2, 2013 at 4:10 PM, Alex Rousskov <rouss...@measurement-factory.com> wrote: > On 12/02/2013 05:23 AM, Kinkie wrote: >>> > My point was that joining SBuf containers is useful for all container >>> > types, but your code only works for std::lists. I think you can provide >>> > the same functionality, with the same level of optimization, by making >>> > the code generic. Here is a sketch: >>> > >>> > { >>> > SBuf::size_type mergedSize = 0; >>> > std::accumulate(..., mergedSize, AddSize(separator)); >>> > >>> > SBuf merged; >>> > merged.reserveSpace(mergedSize); >>> > std::accumulate(..., merged, AddContent(separator)); >>> > >>> > return merged; >>> > } >>> > >>> > The missing "..." parts just contain items.begin(), items.end(), where >>> > bufs is the container. > > >> Ok. >> Let's try to sketch the grand plan, shall we? >> What about using a SBufAlgs.h which contains >> >> SBufEqual >> SBufStartsWith >> SBufAddLength(separator=SBuf()) > > Sounds good to me. I do not think you need a default value for the > separator in the SBufAddLength. > > AFAICT, You will also need an SBufAddContent class "operator" with the > following constructor (similar to SBufAddLength): > > SBufAddContent::SBufAddContent(const SBuf &separator);
Done. > And, if you insist that IsMember() wrapper is needed, it can be placed > in the same header file as well. Make it generic like the SBufJoin() below. It's just convenience. I'd leave SBufList.h / .cc only as convenience helpers, relying on SBufAlgos.h for some grunt work. >> template<class container> SBufContainerJoin<container>(...) > > This one will be more like > > template<class Container> > SBuf > SBufJoin(const Container &items, ...) > { > ... see the sketch above ... > } > > >> plus a specialized SBufListJoin which is simply an instantiation of >> SBufContainerJoin<SBufList>? > > What will that specialization do differently? I do not think we need it > but perhaps I am missing something. As above: just convenience, or an intermediate step towards complete containerization (c->c++ will be hard enough as is, as it will require to have callers use correct encapsulation) Attaching a new revision. -- /kinkie
=== modified file 'src/SBuf.h' --- src/SBuf.h 2013-10-08 04:17:17 +0000 +++ src/SBuf.h 2013-12-02 18:00:42 +0000 @@ -55,6 +55,7 @@ #define SQUIDSBUFPRINT(s) (s).plength(),(s).rawContent() #endif /* SQUIDSBUFPH */ +// TODO: move within SBuf and rename typedef enum { caseSensitive, caseInsensitive === added file 'src/SBufAlgos.h' --- src/SBufAlgos.h 1970-01-01 00:00:00 +0000 +++ src/SBufAlgos.h 2013-12-02 18:00:42 +0000 @@ -0,0 +1,80 @@ +#ifndef SQUID_SBUFALGOS_H_ +#define SQUID_SBUFALGOS_H_ + +#include "SBuf.h" +#include <algorithm> + +/// SBuf equality predicate for STL algorithms etc +class SBufEqual { +public: + explicit SBufEqual(const SBuf &reference, SBufCaseSensitive caseSensitivity_ = caseSensitive) : + reference_(reference), sensitivity_(caseSensitivity_) {} + inline bool operator() (const SBuf & checking) { return 0 == checking.compare(reference_,sensitivity_); } +private: + SBuf reference_; + SBufCaseSensitive sensitivity_; +}; + +/// SBuf "starts with" predicate for STL algorithms etc +class SBufStartsWith { +public: + explicit SBufStartsWith(const SBuf &prefix, SBufCaseSensitive caseSensitive = caseSensitive) : + prefix_(prefix), sensitive(caseSensitive) {} + inline bool operator() (const SBuf & checking) { return checking.startsWith(prefix_,sensitive); } +private: + SBuf prefix_; + SBufCaseSensitive sensitive; +}; + +/** SBuf size addition accumulator for STL contaniners + * + * Equivalent to prefix_length + SBuf.length() + separator.length() + */ +class SBufAddLength { +public: + explicit SBufAddLength(const SBuf &separator) : + separator_len(separator.length()) {} + SBuf::size_type operator()(const SBuf::size_type sz, const SBuf & item) { + return sz + item.length() + separator_len; + } +private: + SBuf::size_type separator_len; +}; + +/// SBuf contents concatenation accumulator for STL containers +class SBufAddContent { +public: + explicit SBufAddContent(const SBuf& separator) : + separator_(separator), first(true) {} + SBuf operator() (SBuf accumulated, const SBuf &item) { + if (first) { + first = false; + accumulated.append(item); + return accumulated; + } + accumulated.append(separator_).append(item); + return accumulated; + } +private: + const SBuf separator_; + bool first; +}; + +/// join all the SBuf in a container of SBuf into a single SBuf, separating with separator +template <class Container> +SBuf +SBufContainerJoin(const Container &items, const SBuf& separator) +{ + // optimization: pre-calculate needed storage + SBuf::size_type sz; + sz = std::accumulate(items.begin(), items.end(), 0, SBufAddLength(separator)); + + SBuf rv; + rv.reserveSpace(sz); + rv = std::accumulate(items.begin(), items.end(), rv, SBufAddContent(separator)); + return rv; +} + + + +#endif /* SQUID_SBUFALGOS_H_ */ === added file 'src/SBufList.cc' --- src/SBufList.cc 1970-01-01 00:00:00 +0000 +++ src/SBufList.cc 2013-12-02 18:00:42 +0000 @@ -0,0 +1,27 @@ +#include "squid.h" +#include "SBufList.h" +#include "SBufAlgos.h" +#include "wordlist.h" + +bool +IsMember(const SBufList & sl, const SBuf &S, const SBufCaseSensitive case_sensitive) +{ + return std::find_if(sl.begin(), sl.end(), SBufEqual(S,case_sensitive)) != sl.end(); +} + +SBuf +SBufListJoin(const SBufList &list, const SBuf &separator) +{ + return SBufContainerJoin(list,separator); +} + +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-02 18:00:42 +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 &, const 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