=== modified file 'src/sbuf/Algorithms.h'
--- src/sbuf/Algorithms.h	2016-02-29 10:11:37 +0000
+++ src/sbuf/Algorithms.h	2016-11-10 19:30:14 +0000
@@ -17,91 +17,113 @@
 /// SBuf equality predicate for STL algorithms etc
 class SBufEqual
 {
 public:
     explicit SBufEqual(const SBuf &reference, SBufCaseSensitive sensitivity = caseSensitive) :
         reference_(reference), sensitivity_(sensitivity) {}
     bool operator() (const SBuf & checking) { return checking.compare(reference_,sensitivity_) == 0; }
 private:
     SBuf reference_;
     SBufCaseSensitive sensitivity_;
 };
 
 /// SBuf "starts with" predicate for STL algorithms etc
 class SBufStartsWith
 {
 public:
     explicit SBufStartsWith(const SBuf &prefix, SBufCaseSensitive sensitivity = caseSensitive) :
         prefix_(prefix), sensitivity_(sensitivity) {}
     bool operator() (const SBuf & checking) { return checking.startsWith(prefix_,sensitivity_); }
 private:
     SBuf prefix_;
     SBufCaseSensitive sensitivity_;
 };
 
 /** SBuf size addition accumulator for STL contaniners
  *
  * Equivalent to prefix_length +  SBuf.length() +  separator.length()
  */
 class SBufAddLength
 {
 public:
     explicit SBufAddLength(const SBuf &separator) :
         separatorLen_(separator.length()) {}
     SBuf::size_type operator()(const SBuf::size_type sz, const SBuf & item) {
         return sz + item.length() + separatorLen_;
     }
 private:
     SBuf::size_type separatorLen_;
 };
 
-/// 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
-    const SBuf::size_type sz = std::accumulate(items.begin(), items.end(), 0, SBufAddLength(separator));
-
-    // sz can be zero in two cases: either items is empty, or all items
-    //  are zero-length. In the former case, we must protect against
-    //  dereferencing the iterator later on, and checking sz is more efficient
-    //  than checking items.size(). This check also provides an optimization
-    //  for the latter case without adding complexity.
-    if (sz == 0)
-        return SBuf();
-
-    SBuf rv;
-    rv.reserveSpace(sz);
+/** Join container of SBufs and append to supplied target
+ *
+ * append to the target SBuf all elements in the [begin,end) range from
+ * an iterable container, prefixed by prefix, separated by separator and
+ * followed by suffix. Prefix and suffix are added also in case of empty
+ * iterable
+ *
+ * \return the modified dest
+ */
+template <class ContainerIterator>
+SBuf&
+JoinContainerIntoSBuf(SBuf &dest, const ContainerIterator &begin,
+		const ContainerIterator &end, const SBuf& separator,
+		const SBuf& prefix = SBuf(), const SBuf& suffix = SBuf())
+{
+    if (begin == end) {
+    	dest.append(prefix).append(suffix);
+        return dest;
+    }
 
-    typename Container::const_iterator i(items.begin());
-    rv.append(*i);
+    // optimization: pre-calculate needed storage
+    const SBuf::size_type totalContainerSize =
+    		std::accumulate(begin, end, 0, SBufAddLength(separator)) +
+			dest.length() + prefix.length() + suffix.length();
+    SBufReservationRequirements req;
+    req.minSpace = totalContainerSize;
+    dest.reserve(req);
+
+    auto i = begin;
+    dest.append(prefix);
+    dest.append(*i);
     ++i;
-    for (; i != items.end(); ++i)
-        rv.append(separator).append(*i);
-    return rv;
+    for (; i != end; ++i)
+        dest.append(separator).append(*i);
+    dest.append(suffix);
+    return dest;
+}
+
+/// convenience wrapper of JoinContainerIntoSBuf with no caller-supplied SBuf
+template <class ContainerIterator>
+SBuf
+JoinContainerToSBuf(const ContainerIterator &begin,
+		const ContainerIterator &end, const SBuf& separator,
+		const SBuf& prefix = SBuf(), const SBuf& suffix = SBuf())
+{
+	SBuf rv;
+	return JoinContainerIntoSBuf(rv, begin, end, separator, prefix, suffix);
 }
 
 namespace std {
 /// default hash functor to support std::unordered_map<SBuf,*>
 template <>
 struct hash<SBuf>
 {
     size_t operator()(const SBuf &) const noexcept;
 };
 }
 
 /** hash functor for SBufs, meant so support case-insensitive std::unordered_map
  *
  * Typical use:
  * \code
  * auto m = std::unordered_map<SBuf, ValueType, CaseInsensitiveSBufHash>();
  * \endcode
  */
 class CaseInsensitiveSBufHash
 {
 public:
     std::size_t operator()(const SBuf &) const noexcept;
 };
 
 #endif /* SQUID_SBUFALGOS_H_ */
 

=== modified file 'src/tests/testSBufList.cc'
--- src/tests/testSBufList.cc	2016-03-01 09:58:44 +0000
+++ src/tests/testSBufList.cc	2016-11-04 06:28:43 +0000
@@ -1,47 +1,53 @@
 /*
  * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
  * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
 #include "squid.h"
 #include "sbuf/Algorithms.h"
 #include "sbuf/List.h"
 #include "tests/testSBufList.h"
 #include "unitTestMain.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(""),SBufContainerJoin(foo,SBuf()));
-    CPPUNIT_ASSERT_EQUAL(SBuf(""),SBufContainerJoin(foo,SBuf()));
+    CPPUNIT_ASSERT_EQUAL(SBuf(""),JoinContainerToSBuf(foo.begin(), foo.end(),SBuf()));
     for (int j = 0; j < sbuf_tokens_number; ++j)
         foo.push_back(tokens[j]);
-    SBuf joined=SBufContainerJoin(foo,SBuf(" "));
+    SBuf joined=JoinContainerToSBuf(foo.begin(), foo.end(),SBuf(" "));
     CPPUNIT_ASSERT_EQUAL(literal,joined);
+    SBuf s1("1"), s2("2"), s3("3"), full("(1,2,3)");
+    SBufList sl{s1,s2,s3};
+    CPPUNIT_ASSERT_EQUAL(full, JoinContainerToSBuf(sl.begin(),
+    		sl.end(), SBuf(","), SBuf("("), SBuf(")")));
+
+    CPPUNIT_ASSERT_EQUAL(SBuf(""),JoinContainerToSBuf(foo.begin(), foo.begin(),SBuf()));
+
 }
 

