Merge lp:~kinkie/squid/stringng into lp:squid/v4

Proposed by Francesco Chemolli
Status: Needs review
Proposed branch: lp:~kinkie/squid/stringng
Merge into: lp:squid/v4
Diff against target: 4264 lines (+3906/-57)
26 files modified
include/util.h (+1/-1)
src/Makefile.am (+58/-11)
src/MemBlob.cc (+11/-0)
src/MemBlob.h (+2/-0)
src/OutOfBoundsException.h (+22/-0)
src/SBuf.cc (+887/-0)
src/SBuf.cci (+174/-0)
src/SBuf.h (+571/-0)
src/SBufExceptions.cc (+72/-0)
src/SBufExceptions.h (+65/-0)
src/SBufExtras.cc (+104/-0)
src/SBufExtras.h (+66/-0)
src/SBufList.cc (+56/-0)
src/SBufList.h (+62/-0)
src/SBufStream.h (+141/-0)
src/SBufTokenizer.cc (+68/-0)
src/SBufTokenizer.h (+149/-0)
src/SBufUtil.cc (+64/-0)
src/SBufUtil.h (+51/-0)
src/SquidString.h (+0/-38)
src/StrList.h (+65/-7)
src/icmp/Makefile.am (+19/-0)
src/tests/SBufFindTest.cc (+418/-0)
src/tests/SBufFindTest.h (+85/-0)
src/tests/testSBuf.cc (+603/-0)
src/tests/testSBuf.h (+92/-0)
To merge this branch: bzr merge lp:~kinkie/squid/stringng
Reviewer Review Type Date Requested Status
Alex Rousskov Pending
Review via email: mp+70503@code.launchpad.net

Description of the change

String-Buffer class, sporting
- refcounted backing store
- efficient substring operations
- mempools and cachemgr integration
- tokenizer
- ostream interface

To post a comment you must log in.
lp:~kinkie/squid/stringng updated
9552. By Francesco Chemolli

Merged from trunk

9553. By Francesco Chemolli

Fixed unit tests linkage

9554. By Francesco Chemolli

Merged from trunk

9555. By Francesco Chemolli

Fixed leftover merge issue

9556. By Francesco Chemolli

fix merge issue

9557. By Francesco Chemolli

fix main Makefile.am

9558. By Francesco Chemolli

Merged from trunk

9559. By Francesco Chemolli

Updated to reflect latest changes to RefCount API.

9560. By Francesco Chemolli

Fix src/Makefile.am typo

9561. By Francesco Chemolli

renamed SBuf::findAny to find_first_of for consistency with std::string

9562. By Francesco Chemolli

Fixed code formatting in Sbuf
Removed terminate() visibility, functionality now merged into c_str()

9563. By Francesco Chemolli

Review and cleanup.

9564. By Francesco Chemolli

Merged from trunk

9565. By Francesco Chemolli

Merged from trunk

9566. By Francesco Chemolli

Automated source formatting

9567. By Francesco Chemolli

Removed SBufSplit, clarified that StrList is incomplete work in progress

9568. By Francesco Chemolli

Updated debug messages in SBuf

9569. By Francesco Chemolli

Improved SBuf unit tests (thanks Amos). Building but tests failing

9570. By Francesco Chemolli

Fixed SBuf unit tests. To be completed

9571. By Francesco Chemolli

Improved SBuf unit tests

9572. By Francesco Chemolli

Updated debug messages to current standards in SBuf

9573. By Francesco Chemolli

Inlined simple SBufTokenizer methods

9574. By Francesco Chemolli

Merged from trunk

9575. By Francesco Chemolli

Changed some parameters in StrList to const &

9576. By Francesco Chemolli

Removed duplicates from src/Makefile.am

9577. By Francesco Chemolli

Removed some junk that crept in in a merge

9578. By Francesco Chemolli

Merged from trunk

9579. By Francesco Chemolli

Reordered private and protected data members in OutOfBoundsException

9580. By Francesco Chemolli

Applied a more consistent formatting to infix operators in SBuf.cc
Bumped some debugs level statements from DBG_DATA to a more standards-consistent level 8

9581. By Francesco Chemolli

Normalized formatting of infix operators and spacing after commas

9582. By Francesco Chemolli

Renamed some parameters for consistency.
Simplified SBuf constructor.

9583. By Francesco Chemolli

CamelCased some SBuf parameters

9584. By Francesco Chemolli

Fixed SBuf::append(), better layering in SBuf::clear(), removed instance of HERE

9585. By Francesco Chemolli

Clarified parameters, improved some find() corner cases.

9586. By Francesco Chemolli

improved some SBuf::find() corner cases, improved documentation~

9587. By Francesco Chemolli

Renamed SBuf::reserve to SBuf::reserveSpace and created a new SBuf::reserve which matches std::string

9588. By Francesco Chemolli

Increased robustness of SBuf size constraints, clarified documentation

9589. By Francesco Chemolli

Clarified SBuf documentation

9590. By Francesco Chemolli

Reverted changes, SBuf uses reserveSpace now. Clarified parameter names

9591. By Francesco Chemolli

Improved bounds-checking on size parameters.
Moved some variable declarations only when actually needed.

9592. By Francesco Chemolli

Made some SBuf::find corner-cases behave more like std::string
Simplified and corrected SBuf::rfind
Increased accuracy and coverage of SBuf unit tests.

9593. By Francesco Chemolli

Reimplemented SBuf::find, increased consistency with std::string

9594. By Francesco Chemolli

Expanded unit tests for SBuf::find

9595. By Francesco Chemolli

Improved SBuf::rfind and its unit test

9596. By Francesco Chemolli

One more SBuf::rfind unit test

9597. By Francesco Chemolli

Added unit test for SBuf::rfind, renamed unclear variable in rfind

9598. By Francesco Chemolli

reworked SBuf::find_first_of, wrote unit test for it.

9599. By Francesco Chemolli

Merged from trunk

9600. By Francesco Chemolli

Fixed headers, made some variables const in SBuf.cc

9601. By Francesco Chemolli

Sorted headers in SBuf files, de-inlined SBuf::reAlloc

9602. By Francesco Chemolli

Simplified and corrected SBuf::rawSpace

9603. By Francesco Chemolli

Renamed SBuf::StorePrototype to InitialStore

9604. By Francesco Chemolli

Changed SBuf::InitialStore to a static function variable

9605. By Francesco Chemolli

Removed misleading comment

9606. By Francesco Chemolli

Changed SBuf exceptions constructors to explicit

9607. By Francesco Chemolli

Reverted unwanted spacing changes in mem.cc

9608. By Francesco Chemolli

Clarified and corrected OutOfBoundsException

9609. By Francesco Chemolli

Simplified OutOfBoundsException's error message handling

9610. By Francesco Chemolli

Merged from trunk

9611. By Francesco Chemolli

Merged from trunk, fixed shadowing problem

9612. By Francesco Chemolli

Changed testSBuf a bit to clarify some tests better

9613. By Francesco Chemolli

Merge SBuf::rfind fixes from Amos Jeffries

9614. By Francesco Chemolli

Merged from trunk

9615. By Francesco Chemolli

Merged SBuf work by Amos Jeffries and Alex Rousskov, including comprehensive find() testsuite.

9616. By Francesco Chemolli

Changed the behavior of SBuf::find to match the inconsistencies of std::string

9617. By Francesco Chemolli

Make SBuf::find consistent, highlighting a bug in some versions of GNU c++stdlib

9618. By Francesco Chemolli

Apply parameter and constant name conventions more consistently.
Document and enforce consistent behavior in handling startPos for SBuf::find methods
Remove useless includes from testSBuf.h

9619. By Francesco Chemolli

Fix bug in SBuf::compare when max comparison length is specified.

9620. By Francesco Chemolli

Deinlined cow(), inlined commonCompareChecksPost()
Added store-size checks to forceSize()
Improved \0-cleanliness in compare()
Implemented cmp() and casecmp() as shorthand versions of compare()
Improved documentation
Added more unit tests

9621. By Francesco Chemolli

Implemented \0-cleanliness for comparison operations
Added more unit-tests.

9622. By Francesco Chemolli

Merged from trunk

9623. By Francesco Chemolli

Fix linking issue in minimum layer

Unmerged revisions

9623. By Francesco Chemolli

Fix linking issue in minimum layer

9622. By Francesco Chemolli

Merged from trunk

9621. By Francesco Chemolli

Implemented \0-cleanliness for comparison operations
Added more unit-tests.

9620. By Francesco Chemolli

Deinlined cow(), inlined commonCompareChecksPost()
Added store-size checks to forceSize()
Improved \0-cleanliness in compare()
Implemented cmp() and casecmp() as shorthand versions of compare()
Improved documentation
Added more unit tests

9619. By Francesco Chemolli

Fix bug in SBuf::compare when max comparison length is specified.

9618. By Francesco Chemolli

Apply parameter and constant name conventions more consistently.
Document and enforce consistent behavior in handling startPos for SBuf::find methods
Remove useless includes from testSBuf.h

9617. By Francesco Chemolli

Make SBuf::find consistent, highlighting a bug in some versions of GNU c++stdlib

9616. By Francesco Chemolli

Changed the behavior of SBuf::find to match the inconsistencies of std::string

9615. By Francesco Chemolli

Merged SBuf work by Amos Jeffries and Alex Rousskov, including comprehensive find() testsuite.

9614. By Francesco Chemolli

Merged from trunk

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/util.h'
2--- include/util.h 2012-10-09 09:23:00 +0000
3+++ include/util.h 2013-07-04 15:56:30 +0000
4@@ -102,7 +102,7 @@
5 extern const char *gb_to_str(const gb_t *);
6 extern void gb_flush(gb_t *); /* internal, do not use this */
7
8-/*
9+/**
10 * Returns the amount of known allocated memory
11 */
12 int statMemoryAccounted(void);
13
14=== modified file 'src/Makefile.am'
15--- src/Makefile.am 2013-06-20 09:56:11 +0000
16+++ src/Makefile.am 2013-07-04 15:56:30 +0000
17@@ -24,7 +24,18 @@
18 SBUF_SOURCE= \
19 base/InstanceId.h \
20 MemBlob.h \
21- MemBlob.cc
22+ MemBlob.cc \
23+ OutOfBoundsException.h \
24+ SBuf.h \
25+ SBuf.cc \
26+ SBufExceptions.h \
27+ SBufExceptions.cc \
28+ SBufTokenizer.h \
29+ SBufTokenizer.cc \
30+ SBufList.h \
31+ SBufList.cc \
32+ SBufUtil.h \
33+ SBufUtil.cc
34
35 LOADABLE_MODULES_SOURCES = \
36 LoadableModule.h \
37@@ -142,7 +153,7 @@
38 UNLINKDSOURCE = unlinkd.h unlinkd.cc
39 UNLINKD = unlinkd
40 else
41-UNLINKDSOURCE = unlinkd.h
42+UNLINKDSOURCE =
43 UNLINKD =
44 endif
45
46@@ -290,7 +301,6 @@
47 client_db.cc \
48 client_side.h \
49 client_side.cc \
50- client_side.h \
51 client_side_reply.cc \
52 client_side_reply.h \
53 client_side_request.cc \
54@@ -298,7 +308,6 @@
55 ClientInfo.h \
56 BodyPipe.cc \
57 BodyPipe.h \
58- ClientInfo.h \
59 ClientRequestContext.h \
60 clientStream.cc \
61 clientStream.h \
62@@ -390,6 +399,7 @@
63 HttpHeaderFieldInfo.h \
64 HttpHeaderTools.h \
65 HttpHeaderTools.cc \
66+ StrList.h \
67 HttpBody.h \
68 HttpBody.cc \
69 HttpControlMsg.h \
70@@ -428,7 +438,6 @@
71 mem.cc \
72 mem_node.cc \
73 mem_node.h \
74- Mem.h \
75 MemBuf.cc \
76 MemObject.cc \
77 MemObject.h \
78@@ -470,6 +479,8 @@
79 send-announce.h \
80 send-announce.cc \
81 $(SBUF_SOURCE) \
82+ SBufExtras.h \
83+ SBufExtras.cc \
84 $(SNMP_SOURCE) \
85 SquidMath.h \
86 SquidMath.cc \
87@@ -482,7 +493,6 @@
88 StatHist.h \
89 StatHist.cc \
90 String.cc \
91- StrList.h \
92 StrList.cc \
93 stmem.cc \
94 stmem.h \
95@@ -592,7 +602,8 @@
96 StoreEntryStream.h \
97 String.cci \
98 SquidString.h \
99- SquidTime.h
100+ SquidTime.h \
101+ SBuf.cci
102
103 BUILT_SOURCES = \
104 cf_gen_defines.cci \
105@@ -1076,7 +1087,7 @@
106 TESTSOURCES= \
107 tests/STUB.h \
108 test_tools.cc \
109- globals.cc
110+ globals.cc
111
112 check_PROGRAMS+=\
113 tests/testBoilerplate \
114@@ -1091,6 +1102,7 @@
115 tests/testStore \
116 tests/testString \
117 tests/testURL \
118+ tests/testSBuf \
119 tests/testConfigParser \
120 tests/testStatHist \
121 tests/testVector \
122@@ -1241,6 +1253,7 @@
123 HttpHeaderFieldInfo.h \
124 HttpHeaderTools.h \
125 HttpHeaderTools.cc \
126+ StrList.h \
127 HttpHdrContRange.cc \
128 HttpHdrRange.cc \
129 HttpHeaderFieldStat.h \
130@@ -1264,7 +1277,6 @@
131 StatCounters.cc \
132 StatCounters.h \
133 StatHist.h \
134- StrList.h \
135 StrList.cc \
136 tests/stub_StatHist.cc \
137 stmem.cc \
138@@ -1472,6 +1484,7 @@
139 HttpHeaderFieldInfo.h \
140 HttpHeaderTools.h \
141 HttpHeaderTools.cc \
142+ StrList.h \
143 HttpHeaderFieldStat.h \
144 HttpHdrCc.h \
145 HttpHdrCc.cc \
146@@ -1534,7 +1547,6 @@
147 StatCounters.h \
148 StatCounters.cc \
149 StatHist.h \
150- StrList.h \
151 StrList.cc \
152 tests/stub_StatHist.cc \
153 stmem.cc \
154@@ -2207,7 +2219,6 @@
155 StatCounters.cc \
156 StatHist.h \
157 StatHist.cc \
158- Mem.h \
159 stmem.cc \
160 repl_modules.h \
161 store.cc \
162@@ -3825,6 +3836,42 @@
163 $(REPL_OBJS) \
164 $(SQUID_CPPUNIT_LA)
165
166+tests_testSBuf_SOURCES= \
167+ tests/testSBuf.h \
168+ tests/testSBuf.cc \
169+ tests/testMain.cc \
170+ tests/SBufFindTest.h \
171+ tests/SBufFindTest.cc \
172+ $(SBUF_SOURCE) \
173+ SBufStream.h \
174+ time.cc \
175+ mem.cc \
176+ tests/stub_debug.cc \
177+ tests/stub_fatal.cc \
178+ tests/stub_HelperChildConfig.cc \
179+ tests/stub_cache_cf.cc \
180+ tests/stub_cache_manager.cc \
181+ tests/stub_store.cc \
182+ tests/stub_store_stats.cc \
183+ tests/stub_tools.cc \
184+ SquidString.h \
185+ String.cc \
186+ wordlist.cc \
187+ MemBuf.cc
188+nodist_tests_testSBuf_SOURCES=$(TESTSOURCES)
189+tests_testSBuf_LDFLAGS = $(LIBADD_DL)
190+tests_testSBuf_LDADD=\
191+ $(SQUID_CPPUNIT_LIBS) \
192+ $(SQUID_CPPUNIT_LA) \
193+ $(COMPAT_LIB) \
194+ libsquid.la \
195+ ip/libip.la \
196+ mgr/libmgr.la \
197+ base/libbase.la \
198+ $(top_builddir)/lib/libmiscutil.la \
199+ $(COMMON_LIBS)
200+tests_testSBuf_DEPENDENCIES= $(SQUID_CPPUNIT_LA)
201+
202 tests_testConfigParser_SOURCES = \
203 ClientInfo.h \
204 Mem.h \
205
206=== modified file 'src/MemBlob.cc'
207--- src/MemBlob.cc 2012-11-15 22:12:03 +0000
208+++ src/MemBlob.cc 2013-07-04 15:56:30 +0000
209@@ -46,6 +46,17 @@
210 MemBlobStats::MemBlobStats(): alloc(0), live(0), append(0), liveBytes(0)
211 {}
212
213+MemBlobStats&
214+MemBlobStats::operator += (const MemBlobStats& s)
215+{
216+ alloc+=s.alloc;
217+ live+=s.live;
218+ append+=s.append;
219+ liveBytes+=s.liveBytes;
220+
221+ return *this;
222+}
223+
224 std::ostream&
225 MemBlobStats::dump(std::ostream &os) const
226 {
227
228=== modified file 'src/MemBlob.h'
229--- src/MemBlob.h 2012-10-29 04:59:58 +0000
230+++ src/MemBlob.h 2013-07-04 15:56:30 +0000
231@@ -46,6 +46,8 @@
232 /// dumps class-wide statistics
233 std::ostream& dump(std::ostream& os) const;
234
235+ MemBlobStats& operator += (const MemBlobStats&);
236+
237 public:
238 uint64_t alloc; ///< number of MemBlob instances created so far
239 uint64_t live; ///< number of MemBlob instances currently alive
240
241=== added file 'src/OutOfBoundsException.h'
242--- src/OutOfBoundsException.h 1970-01-01 00:00:00 +0000
243+++ src/OutOfBoundsException.h 2013-07-04 15:56:30 +0000
244@@ -0,0 +1,22 @@
245+#ifndef _SQUID_SRC_OUTOFBOUNDSEXCEPTION_H
246+#define _SQUID_SRC_OUTOFBOUNDSEXCEPTION_H
247+
248+#include "base/TextException.h"
249+#include "SBuf.h"
250+
251+/**
252+ * Exception raised when the user is going out of bounds when accessing
253+ * a char within the SBuf
254+ */
255+class OutOfBoundsException : public TextException
256+{
257+public:
258+ OutOfBoundsException(const SBuf &buf, SBuf::size_type &pos, const char *aFileName = 0, int aLineNo = -1);
259+ virtual ~OutOfBoundsException() throw();
260+
261+protected:
262+ SBuf _buf;
263+ SBuf::size_type _pos;
264+};
265+
266+#endif /* _SQUID_SRC_OUTOFBOUNDSEXCEPTION_H */
267
268=== added file 'src/SBuf.cc'
269--- src/SBuf.cc 1970-01-01 00:00:00 +0000
270+++ src/SBuf.cc 2013-07-04 15:56:30 +0000
271@@ -0,0 +1,887 @@
272+/*
273+ * SBuf.cc (C) 2008 Francesco Chemolli <kinkie@squid-cache.org>
274+ *
275+ * SQUID Web Proxy Cache http://www.squid-cache.org/
276+ * ----------------------------------------------------------
277+ *
278+ * Squid is the result of efforts by numerous individuals from
279+ * the Internet community; see the CONTRIBUTORS file for full
280+ * details. Many organizations have provided support for Squid's
281+ * development; see the SPONSORS file for full details. Squid is
282+ * Copyrighted (C) 2001 by the Regents of the University of
283+ * California; see the COPYRIGHT file for full details. Squid
284+ * incorporates software developed and/or copyrighted by other
285+ * sources; see the CREDITS file for full details.
286+ *
287+ * This program is free software; you can redistribute it and/or modify
288+ * it under the terms of the GNU General Public License as published by
289+ * the Free Software Foundation; either version 2 of the License, or
290+ * (at your option) any later version.
291+ *
292+ * This program is distributed in the hope that it will be useful,
293+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
294+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
295+ * GNU General Public License for more details.
296+ *
297+ * You should have received a copy of the GNU General Public License
298+ * along with this program; if not, write to the Free Software
299+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
300+ */
301+
302+#include "squid.h"
303+#include "base/RefCount.h"
304+#include "Debug.h"
305+#include "OutOfBoundsException.h"
306+#include "SBuf.h"
307+#include "SBufExceptions.h"
308+#include "util.h"
309+
310+#if HAVE_STRING_H
311+#include <string.h>
312+#endif
313+
314+#if HAVE_SSTREAM
315+#include <sstream>
316+#endif
317+
318+#if HAVE_IOSTREAM
319+#include <iostream>
320+#endif
321+
322+#ifdef VA_COPY
323+#undef VA_COPY
324+#endif
325+#if defined HAVE_VA_COPY
326+#define VA_COPY va_copy
327+#elif defined HAVE___VA_COPY
328+#define VA_COPY __va_copy
329+#endif
330+
331+InstanceIdDefinitions(SBuf, "SBuf");
332+
333+SBufStats SBuf::stats;
334+const SBuf::size_type SBuf::npos;
335+const SBuf::size_type SBuf::maxSize;
336+
337+
338+SBufStats::SBufStats()
339+ : alloc(0), allocCopy(0), allocFromString(0), allocFromCString(0),
340+ assignFast(0), clear(0), append(0), toStream(0), setChar(0),
341+ getChar(0), compareSlow(0), compareFast(0), copyOut(0),
342+ rawAccess(0), chop(0), trim(0), find(0), scanf(0),
343+ caseChange(0), cowFast(0), cowSlow(0), live(0)
344+{}
345+
346+SBufStats&
347+SBufStats::operator +=(const SBufStats& ss)
348+{
349+ alloc += ss.alloc;
350+ allocCopy += ss.allocCopy;
351+ allocFromString += ss.allocFromString;
352+ allocFromCString += ss.allocFromCString;
353+ assignFast += ss.assignFast;
354+ clear += ss.clear;
355+ append += ss.append;
356+ toStream += ss.toStream;
357+ setChar += ss.setChar;
358+ getChar += ss.getChar;
359+ compareSlow += ss.compareSlow;
360+ compareFast += ss.compareFast;
361+ copyOut += ss.copyOut;
362+ rawAccess += ss.rawAccess;
363+ chop += ss.chop;
364+ trim += ss.trim;
365+ find += ss.find;
366+ scanf += ss.scanf;
367+ caseChange += ss.caseChange;
368+ cowFast += ss.cowFast;
369+ cowSlow += ss.cowSlow;
370+ live += ss.live;
371+
372+ return *this;
373+}
374+
375+SBuf::SBuf()
376+ : store_(GetStorePrototype()), off_(0), len_(0)
377+{
378+ debugs(24, 8, id << " created");
379+ ++stats.alloc;
380+ ++stats.live;
381+}
382+
383+SBuf::SBuf(const SBuf &S)
384+ : store_(S.store_), off_(S.off_), len_(S.len_)
385+{
386+ debugs(24, 8, id << " created from id " << S.id);
387+ ++stats.alloc;
388+ ++stats.allocCopy;
389+ ++stats.live;
390+}
391+
392+SBuf::SBuf(const String &S)
393+ : store_(GetStorePrototype()), off_(0), len_(0)
394+{
395+ debugs(24, 8, id << " created from string");
396+ assign(S.rawBuf(), 0, S.size());
397+ ++stats.alloc;
398+ ++stats.allocFromString;
399+ ++stats.live;
400+}
401+
402+SBuf::SBuf(const char *S, size_type pos, size_type n)
403+ : store_(GetStorePrototype()), off_(0), len_(0)
404+{
405+ append(S,pos,n); //bounds checked in append()
406+ ++stats.alloc;
407+ ++stats.allocFromCString;
408+ ++stats.live;
409+}
410+
411+SBuf::~SBuf()
412+{
413+ debugs(24, 8, id << " destructed");
414+ --stats.live;
415+}
416+
417+SBuf&
418+SBuf::assign(const SBuf &S)
419+{
420+ debugs(24, 7, "assigning " << id << " from " << S.id);
421+ if (&S == this) //assignment to self. Noop.
422+ return *this;
423+ ++stats.assignFast;
424+ store_ = S.store_;
425+ off_ = S.off_;
426+ len_ = S.len_;
427+ return *this;
428+}
429+
430+SBuf&
431+SBuf::assign(const char *S, size_type pos, size_type n)
432+{
433+ debugs(24, 6, id << " from c-string, pos=" << pos << "n=" << n << ")");
434+ clear();
435+ return append(S, pos, n); //bounds checked in append()
436+}
437+
438+void
439+SBuf::reserveCapacity(size_type minCapacity)
440+{
441+ Must(0 <= minCapacity && minCapacity <= maxSize);
442+ reserveSpace(minCapacity-length());
443+}
444+
445+void
446+SBuf::reserveSpace(size_type minSpace)
447+{
448+ Must(0 <= minSpace && minSpace <= maxSize);
449+ debugs(24, 7, "reserving " << minSpace << " for " << id);
450+ // we're not concerned about RefCounts here,
451+ // the store knows the last-used portion. If
452+ // it's available, we're effectively claiming ownership
453+ // of it. If it's not, we need to go away (realloc)
454+ if (store_->canAppend(off_+len_, minSpace)) {
455+ debugs(24, 7, "not growing");
456+ return;
457+ }
458+ // TODO: we may try to memmove before realloc'ing in order to avoid
459+ // one allocation operation, if we're the sole owners of a MemBlob.
460+ // Maybe some heuristic on off_ and length()?
461+ reAlloc(estimateCapacity(minSpace+length()));
462+}
463+
464+void
465+SBuf::clear()
466+{
467+#if 0
468+ //enabling this code path, the store will be freed and reinitialized
469+ store_ = GetStorePrototype(); //uncomment to actually free storage upon clear()
470+#else
471+ //enabling this code path, we try to release the store without deallocating it.
472+ // will be lazily reallocated if needed.
473+ if (store_->LockCount() == 1)
474+ store_->clear();
475+#endif
476+ len_ = 0;
477+ off_ = 0;
478+ ++stats.clear;
479+}
480+
481+SBuf&
482+SBuf::append(const SBuf &S)
483+{
484+ return append(S.buf(), 0, S.length());
485+}
486+
487+SBuf&
488+SBuf::append(const char * S, size_type pos, size_type n)
489+{
490+ Must(pos == npos || pos >= 0);
491+ Must(n == npos || n >= 0);
492+
493+ if (S == NULL)
494+ return *this;
495+ if (n == npos)
496+ n = strlen(S)-pos;
497+
498+ debugs(24, 7, "from c-string to id " << id);
499+
500+ reserveSpace(n); //called method also checks n <= maxSize()
501+ const char *actual_start = S+pos;
502+ store_->append(actual_start, n);
503+ len_ += n;
504+ ++stats.append;
505+ return *this;
506+}
507+
508+SBuf&
509+SBuf::append(const std::string &str, SBuf::size_type pos, SBuf::size_type n)
510+{
511+ return append(str.data(), pos, n); //bounds checked in append()
512+}
513+
514+SBuf&
515+SBuf::assign(const std::string &str, size_type pos, size_type n)
516+{
517+ clear();
518+ return append(str, pos, n); //bounds checked in append()
519+}
520+
521+SBuf&
522+SBuf::Printf(const char *fmt, ...)
523+{
524+ va_list args;
525+ va_start(args, fmt);
526+ clear();
527+ vappendf(fmt, args);
528+ va_end(args);
529+ return *this;
530+}
531+
532+SBuf&
533+SBuf::appendf(const char *fmt, ...)
534+{
535+ va_list args;
536+ va_start(args, fmt);
537+ vappendf(fmt, args);
538+ va_end(args);
539+ return *this;
540+}
541+
542+SBuf&
543+SBuf::vappendf(const char *fmt, va_list vargs)
544+{
545+#ifdef VA_COPY
546+ va_list ap;
547+#endif
548+ int sz = 0;
549+
550+ Must(fmt != NULL);
551+
552+ //we can assume that we'll need to append at least strlen(fmt) bytes,
553+ //times 1.2 for instance...
554+ reserveSpace(strlen(fmt)*2);
555+
556+ while (length() <= maxSize) {
557+#ifdef VA_COPY
558+ /* Fix of bug 753r. The value of vargs is undefined
559+ * after vsnprintf() returns. Make a copy of vargs
560+ * in case we loop around and call vsnprintf() again.
561+ */
562+ VA_COPY(ap, vargs);
563+ sz = vsnprintf(bufEnd(), store_->spaceSize(), fmt, ap);
564+ va_end(ap);
565+#else /* VA_COPY */
566+ sz = vsnprintf(bufEnd(), store_->spaceSize(), fmt, vargs);
567+#endif /* VA_COPY*/
568+ /* check for possible overflow */
569+ /* snprintf on Linux returns -1 on overflows */
570+ /* snprintf on FreeBSD returns at least free_space on overflows */
571+
572+ if (sz < 0 || sz >= (int)store_->spaceSize())
573+ reserveSpace(sz*2); // TODO: tune heuristics
574+ else
575+ break;
576+ }
577+
578+ len_ += sz;
579+ // TODO: this does NOT belong here, but to class-init or autoconf
580+ /* on Linux and FreeBSD, '\0' is not counted in return value */
581+ /* on XXX it might be counted */
582+ /* check that '\0' is appended and not counted */
583+
584+ if (operator[](len_-1) == 0) {
585+ --sz;
586+ --len_;
587+ }
588+
589+ store_->size += sz;
590+ ++stats.append;
591+
592+ return *this;
593+}
594+
595+std::ostream&
596+SBuf::print(std::ostream &os) const
597+{
598+ os.write(buf(), length());
599+ ++stats.toStream;
600+ return os;
601+}
602+
603+std::ostream&
604+SBuf::dump(std::ostream &os) const
605+{
606+ os << id
607+ << ": ";
608+ store_->dump(os);
609+ os << ",offset:" << off_
610+ << ",len:" << len_
611+ << ") : '";
612+ print(os);
613+ os << std::endl;
614+ return os;
615+}
616+
617+void
618+SBuf::setAt(SBuf::size_type pos, char toset)
619+{
620+ checkAccessBounds(pos);
621+ cow();
622+ store_->mem[off_+pos] = toset;
623+ ++stats.setChar;
624+}
625+
626+static int
627+memcasecmp(const char *b1, const char *b2, SBuf::size_type len)
628+{
629+ int rv=0;
630+ while (len > 0) {
631+ rv = tolower(*b1)-tolower(*b2);
632+ if (rv != 0)
633+ return rv;
634+ ++b1;
635+ ++b2;
636+ --len;
637+ }
638+ return rv;
639+}
640+
641+int
642+SBuf::compare(const SBuf &S, SBufCaseSensitive isCaseSensitive, size_type n) const
643+{
644+ Must(n == npos || n >= 0);
645+ size_type sz = min(S.length(), length());
646+ if (n != npos)
647+ sz = min(n, sz);
648+ ++stats.compareSlow;
649+ int rv;
650+ if (isCaseSensitive == caseSensitive) {
651+ rv = memcmp(buf(), S.buf(), sz);
652+ } else {
653+ rv = memcasecmp(buf(), S.buf(), sz);
654+ }
655+ if (rv != 0)
656+ return rv;
657+ // the first sz bytes are equal. If the user asked to ignore the rest
658+ // by specifying n and no SBuf was shorter than it, the result is final
659+ if (n == sz)
660+ return 0;
661+ //first sz bytes equal. longest SBuf "wins"
662+ if (length() == S.length()) //they're REALLY the same..
663+ return 0;
664+ if (length() > S.length())
665+ return 1;
666+ return -1;
667+
668+}
669+
670+bool
671+SBuf::startsWith(const SBuf &S, SBufCaseSensitive isCaseSensitive) const
672+{
673+ if (length() < S.length()) {
674+ ++stats.compareFast;
675+ return false;
676+ }
677+ return (compare(S, isCaseSensitive, S.length()) == 0);
678+}
679+
680+bool
681+SBuf::operator ==(const SBuf & S) const
682+{
683+ debugs(24, 8, id << " == " << S.id);
684+ if (length() != S.length()) {
685+ debugs(24, 8, "no, different lengths");
686+ ++stats.compareFast;
687+ return false; //shortcut: must be equal length
688+ }
689+ if (store_ == S.store_ && off_ == S.off_) {
690+ debugs(24, 8, "yes, same length and backing store");
691+ ++stats.compareFast;
692+ return true; //shortcut: same store, offset and length
693+ }
694+ ++stats.compareSlow;
695+ const bool rv = (0 == strncmp(buf(), S.buf(), length()));
696+ debugs(24, 8, "returning " << rv);
697+ return rv;
698+}
699+
700+bool
701+SBuf::operator !=(const SBuf & S) const
702+{
703+ return !(*this == S);
704+}
705+
706+SBuf
707+SBuf::consume(SBuf::size_type n)
708+{
709+ Must (n == npos || n >= 0);
710+ if (n == npos)
711+ n = length();
712+ else
713+ n = min(n, length());
714+ SBuf rv(substr(0, n));
715+ chop(n);
716+ return rv;
717+}
718+
719+const
720+SBufStats& SBuf::GetStats()
721+{
722+ return stats;
723+}
724+
725+SBuf::size_type
726+SBuf::copy(char *dest, SBuf::size_type n) const
727+{
728+ Must(n >= 0);
729+
730+ SBuf::size_type toexport = length();
731+ if (toexport > n)
732+ toexport = n;
733+
734+ memcpy(dest, buf(), toexport);
735+
736+ ++stats.copyOut;
737+ return toexport;
738+}
739+
740+const char*
741+SBuf::rawContent() const
742+{
743+ ++stats.rawAccess;
744+ return buf();
745+}
746+
747+char *
748+SBuf::rawSpace(size_type minSize)
749+{
750+ cow(minSize+length());
751+ ++stats.rawAccess;
752+ return bufEnd();
753+}
754+
755+void
756+SBuf::forceSize(SBuf::size_type newSize)
757+{
758+ Must(store_->LockCount() == 1);
759+ if (newSize > min(SBuf::maxSize,store_->capacity-off_))
760+ throw SBufTooBigException(__FILE__,__LINE__);
761+ len_ = newSize;
762+ store_->size = newSize;
763+}
764+
765+const char*
766+SBuf::c_str()
767+{
768+ ++stats.rawAccess;
769+ /* null-terminate the current buffer, by hand-appending a \0 at its tail but
770+ * without increasing its length. May COW, the side-effect is to guarantee that
771+ * the MemBlob's tail is availabe for us to use */
772+ *rawSpace(1) = '\0';
773+ ++store_->size;
774+ ++stats.setChar;
775+ return buf();
776+}
777+
778+SBuf&
779+SBuf::chop(SBuf::size_type pos, SBuf::size_type n)
780+{
781+ Must(pos >= 0);
782+ Must(n == npos || n >= 0);
783+ /*
784+ * TODO: possible optimization: if the SBuf is at the tail of the
785+ * MemBlob we could decrease the MemBlob tail-pointer so that a subsequent
786+ * append will reuse the freed space.
787+ */
788+ if (pos > length() || n == 0) {
789+ clear();
790+ return *this;
791+ }
792+ if (n == npos || (pos+n) > length())
793+ n = length()-pos;
794+ ++stats.chop;
795+ off_ += pos;
796+ len_ = n;
797+ return *this;
798+}
799+
800+SBuf&
801+SBuf::trim(const SBuf &toRemove, bool atBeginning, bool atEnd)
802+{
803+ ++stats.trim;
804+ if (atEnd) {
805+ const char *p = bufEnd()-1;
806+ while (!isEmpty() && memchr(toRemove.buf(), *p, toRemove.length()) != NULL) {
807+ //current end-of-buf is in the searched set
808+ --len_;
809+ --p;
810+ }
811+ }
812+ if (atBeginning) {
813+ const char *p = buf();
814+ while (!isEmpty() && memchr(toRemove.buf(), *p, toRemove.length()) != NULL) {
815+ --len_;
816+ ++off_;
817+ ++p;
818+ }
819+ }
820+ if (isEmpty())
821+ clear();
822+ return *this;
823+}
824+
825+SBuf
826+SBuf::substr(SBuf::size_type pos, SBuf::size_type n) const
827+{
828+ SBuf rv(*this);
829+ rv.chop(pos, n); //stats handled by callee
830+ return rv;
831+}
832+
833+SBuf::size_type
834+SBuf::find(char c, SBuf::size_type startPos) const
835+{
836+ ++stats.find;
837+
838+ // std::string presents npos if needle is outside hay
839+ if (startPos >= length())
840+ return npos;
841+
842+ if (startPos < 0)
843+ return npos;
844+
845+ // for npos with char sd::string returns npos
846+ // this differs from how std::string handles 1-length string
847+ if (startPos == npos)
848+ return npos;
849+
850+ const void *i = memchr(buf()+startPos, (int)c, (size_type)length()-startPos);
851+
852+ if (i == NULL)
853+ return npos;
854+
855+ return (static_cast<const char *>(i)-buf());
856+}
857+
858+SBuf::size_type
859+SBuf::find(const SBuf &needle, size_type startPos) const
860+{
861+ // std::string allows needle to overhang hay but not start outside
862+ if (startPos != npos && startPos > length()) {
863+ ++stats.find;
864+ return npos;
865+ }
866+
867+ // for empty needle std::string returns startPos
868+ if (needle.length() == 0) {
869+ ++stats.find;
870+ return startPos;
871+ }
872+
873+ // for npos with char* std::string scans entire hay
874+ // this differs from how std::string handles single char from npos
875+ if (startPos == npos)
876+ return npos;
877+
878+ // if needle length is 1 use the char search
879+ if (needle.length() == 1)
880+ return find(needle[0], startPos);
881+
882+ ++stats.find;
883+
884+ char *begin = buf()+startPos;
885+ char *lastPossible = buf()+length()-needle.length()+1;
886+ char needleBegin = needle[0];
887+
888+ debugs(24, 7, "looking for " << needle << "starting at " << startPos <<
889+ " in id " << id);
890+ while (begin < lastPossible) {
891+ char *tmp;
892+ debugs(24, 8, " begin=" << (void *) begin <<
893+ ", lastPossible=" << (void*) lastPossible );
894+ tmp = static_cast<char *>(memchr(begin, needleBegin, lastPossible-begin));
895+ if (tmp == NULL) {
896+ debugs(24, 8 , "First byte not found");
897+ return npos;
898+ }
899+ // lastPossible guarrantees no out-of-bounds with memcmp()
900+ if (0 == memcmp(needle.buf(), tmp, needle.length())) {
901+ debugs(24, 8, "Found at " << (tmp-buf()));
902+ return (tmp-buf());
903+ }
904+ begin = tmp+1;
905+ }
906+ debugs(24, 8, "not found");
907+ return npos;
908+}
909+
910+SBuf::size_type
911+SBuf::rfind(const SBuf &needle, SBuf::size_type endPos) const
912+{
913+ // when the needle is 1 char, use the 1-char rfind()
914+ if (needle.length() == 1)
915+ return rfind(needle[0], endPos);
916+
917+ ++stats.find;
918+
919+ // on npos input std::string scans from the end of hay
920+ if (endPos == npos || endPos > length())
921+ endPos=length();
922+
923+ // on empty hay std::string returns npos
924+ if (length() < needle.length())
925+ return npos;
926+
927+ // on empty needle std::string returns the position the search starts
928+ if (needle.length() == 0)
929+ return endPos;
930+
931+/* std::string permits needle to overhang endPos
932+ if (endPos <= needle.length())
933+ return npos;
934+*/
935+
936+ char *bufBegin = buf();
937+ char *cur = bufBegin+endPos;
938+ char needleBegin = needle[0];
939+ while (cur >= bufBegin) {
940+ if (*cur == needleBegin) {
941+ if (0 == memcmp(needle.buf(), cur, needle.length())) {
942+ // found
943+ return (cur-buf());
944+ }
945+ }
946+ --cur;
947+ }
948+ return npos;
949+}
950+
951+SBuf::size_type
952+SBuf::rfind(char c, SBuf::size_type endPos) const
953+{
954+ ++stats.find;
955+
956+ // on empty hay std::string returns size of hay
957+ if (length() < 1)
958+ return npos;
959+
960+ // on npos input std::string compares last octet of hay
961+ if (endPos == npos || endPos >= length())
962+ endPos=length();
963+ else {
964+ // NP: off-by-one weirdness:
965+ // endPos is an offset ... 0-based
966+ // length() is a count ... 1-based
967+ // memrhr() requires a 1-based count of space to scan.
968+ ++endPos;
969+ }
970+
971+ const void *i = memrchr(buf(), (int)c, (size_type)endPos);
972+
973+ if (i == NULL)
974+ return npos;
975+
976+ return (static_cast<const char *>(i)-buf());
977+}
978+
979+SBuf::size_type
980+SBuf::find_first_of(const SBuf &set, size_type startPos) const
981+{
982+ Must(startPos == npos || startPos >= 0);
983+ ++stats.find;
984+
985+ if (set.length() == 0)
986+ return 0;
987+
988+ debugs(24, 7, "any of '" << set << "' " << " in id " << id);
989+ if (startPos == npos || startPos > length())
990+ return npos;
991+ startPos = min(startPos, length());
992+ char *cur = buf()+startPos, *end = bufEnd();
993+ while (cur < end) {
994+ if (memchr(set.buf(), *cur, set.length()))
995+ return (cur-buf());
996+ ++cur;
997+ }
998+ debugs(24, 7, "not found");
999+ return npos;
1000+}
1001+
1002+/*
1003+ * TODO: borrow a sscanf implementation from Linux or similar?
1004+ * we'd really need a vsnscanf(3)... ? As an alternative, a
1005+ * light-regexp-like domain-specific syntax might be an idea.
1006+ */
1007+int
1008+SBuf::scanf(const char *format, ...)
1009+{
1010+ va_list arg;
1011+ int rv;
1012+ ++stats.scanf;
1013+ va_start(arg, format);
1014+ rv = vsscanf(c_str(), format, arg);
1015+ va_end(arg);
1016+ return rv;
1017+}
1018+
1019+std::ostream &
1020+operator <<(std::ostream& os, const SBuf& S)
1021+{
1022+ return S.print(os);
1023+}
1024+
1025+std::ostream &
1026+SBufStats::dump(std::ostream& os) const
1027+{
1028+ MemBlobStats ststats = MemBlob::GetStats();
1029+ os <<
1030+ "SBuf stats:\nnumber of allocations: " << alloc <<
1031+ "\ncopy-allocations: " << allocCopy <<
1032+ "\ncopy-allocations from SquidString: " << allocFromString <<
1033+ "\ncopy-allocations from C String: " << allocFromCString <<
1034+ "\nlive references: " << live <<
1035+ "\nno-copy assignments: " << assignFast <<
1036+ "\nclearing operations: " << clear <<
1037+ "\nappend operations: " << append <<
1038+ "\ndump-to-ostream: " << toStream <<
1039+ "\nset-char: " << setChar <<
1040+ "\nget-char: " << getChar <<
1041+ "\ncomparisons with data-scan: " << compareSlow <<
1042+ "\ncomparisons not requiring data-scan: " << compareFast <<
1043+ "\ncopy-out ops: " << copyOut <<
1044+ "\nraw access to memory: " << rawAccess <<
1045+ "\nchop operations: " << chop <<
1046+ "\ntrim operations: " << trim <<
1047+ "\nfind: " << find <<
1048+ "\nscanf: " << scanf <<
1049+ "\ncase-change ops: " << caseChange <<
1050+ "\nCOW not actually requiring a copy: " << cowFast <<
1051+ "\nCOW: " << cowSlow <<
1052+ "\naverage store share factor: " <<
1053+ (ststats.live != 0 ? static_cast<float>(live)/ststats.live : 0) <<
1054+ std::endl;
1055+ return os;
1056+}
1057+
1058+SBuf
1059+SBuf::toLower() const
1060+{
1061+ debugs(24, 8, "\"" << *this << "\"");
1062+ SBuf rv(*this);
1063+ for (size_type j = 0; j < length(); ++j) {
1064+ const int c = (*this)[j];
1065+ if (isupper(c))
1066+ rv.setAt(j, tolower(c)); //will cow() if needed
1067+ }
1068+ debugs(24, 8, "result: \"" << *this << "\"");
1069+ ++stats.caseChange;
1070+ return rv;
1071+}
1072+
1073+SBuf
1074+SBuf::toUpper() const
1075+{
1076+ debugs(24, 8, "\"" << *this << "\"");
1077+ SBuf rv(*this);
1078+ for (size_type j = 0; j < length(); ++j) {
1079+ const int c = (*this)[j];
1080+ if (islower(c))
1081+ rv.setAt(j, toupper(c)); //will cow() if needed
1082+ }
1083+ debugs(24, 8, "result: \"" << *this << "\"");
1084+ ++stats.caseChange;
1085+ return rv;
1086+}
1087+
1088+/**
1089+ * checks whether the requested 'pos' is within the bounds of the SBuf
1090+ * \throw OutOfBoundsException if access is out of bounds
1091+ */
1092+void
1093+SBuf::checkAccessBounds(SBuf::size_type pos) const
1094+{
1095+ if (pos < 0)
1096+ throw OutOfBoundsException(*this, pos, __FILE__, __LINE__);
1097+ if (pos > length())
1098+ throw OutOfBoundsException(*this, pos, __FILE__, __LINE__);
1099+}
1100+
1101+String
1102+SBuf::toString() const
1103+{
1104+ String rv;
1105+ rv.limitInit(buf(), length());
1106+ ++stats.copyOut;
1107+ return rv;
1108+}
1109+
1110+/*
1111+ * re-allocate the backing store of the SBuf.
1112+ * If there are contents in the SBuf, they will be copied over.
1113+ * NO verifications are made on the size parameters, it's up to the caller to
1114+ * make sure that the new size is big enough to hold the copied contents.
1115+ * The re-allocated storage MAY be bigger than the requested size due to size-chunking
1116+ * algorithms in MemBlock, it is guarranteed NOT to be smaller.
1117+ */
1118+void
1119+SBuf::reAlloc(SBuf::size_type newsize)
1120+{
1121+ debugs(24, DBG_DATA, "new size: " << newsize);
1122+ if (newsize > maxSize)
1123+ throw SBufTooBigException(__FILE__, __LINE__);
1124+ MemBlob::Pointer newbuf = new MemBlob(newsize);
1125+ if (length() > 0)
1126+ newbuf->append(buf(), length());
1127+ store_ = newbuf;
1128+ off_ = 0;
1129+ ++stats.cowSlow;
1130+ debugs(24, 7, "new store capacity: " << store_->capacity);
1131+}
1132+
1133+/**
1134+ * copy-on-write: make sure that we are the only holder of the backing store.
1135+ * If not, reallocate. If a new size is specified, and it is greater than the
1136+ * current length, the backing store will be extended as needed
1137+ * \retval false no grow was needed
1138+ * \retval true had to copy
1139+ */
1140+bool
1141+SBuf::cow(SBuf::size_type newsize)
1142+{
1143+ debugs(24, DBG_DATA, "new size:" << newsize);
1144+ if (newsize == npos || newsize < length())
1145+ newsize = length();
1146+
1147+ if (store_->LockCount() == 1 && newsize == length()) {
1148+ debugs(24, DBG_DATA, "no cow needed");
1149+ ++stats.cowFast;
1150+ return false;
1151+ }
1152+ reAlloc(newsize);
1153+ return true;
1154+}
1155+
1156+#if !_USE_INLINE_
1157+#include "SBuf.cci"
1158+#endif
1159
1160=== added file 'src/SBuf.cci'
1161--- src/SBuf.cci 1970-01-01 00:00:00 +0000
1162+++ src/SBuf.cci 2013-07-04 15:56:30 +0000
1163@@ -0,0 +1,174 @@
1164+/*
1165+ * SBuf.cc (C) 2008 Francesco Chemolli <kinkie@squid-cache.org>
1166+ *
1167+ * SQUID Web Proxy Cache http://www.squid-cache.org/
1168+ * ----------------------------------------------------------
1169+ *
1170+ * Squid is the result of efforts by numerous individuals from
1171+ * the Internet community; see the CONTRIBUTORS file for full
1172+ * details. Many organizations have provided support for Squid's
1173+ * development; see the SPONSORS file for full details. Squid is
1174+ * Copyrighted (C) 2001 by the Regents of the University of
1175+ * California; see the COPYRIGHT file for full details. Squid
1176+ * incorporates software developed and/or copyrighted by other
1177+ * sources; see the CREDITS file for full details.
1178+ *
1179+ * This program is free software; you can redistribute it and/or modify
1180+ * it under the terms of the GNU General Public License as published by
1181+ * the Free Software Foundation; either version 2 of the License, or
1182+ * (at your option) any later version.
1183+ *
1184+ * This program is distributed in the hope that it will be useful,
1185+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1186+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1187+ * GNU General Public License for more details.
1188+ *
1189+ * You should have received a copy of the GNU General Public License
1190+ * along with this program; if not, write to the Free Software
1191+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
1192+ */
1193+
1194+#include "base/RefCount.h"
1195+#include "OutOfBoundsException.h"
1196+#include "SBufExceptions.h"
1197+
1198+#if HAVE_CLIMITS
1199+#include <climits>
1200+#elif HAVE_LIMITS_H
1201+#include <limits.h>
1202+#endif
1203+
1204+SBuf&
1205+SBuf::operator =(const SBuf & S)
1206+{
1207+ return assign(S);
1208+}
1209+
1210+SBuf&
1211+SBuf::operator =(const char *S)
1212+{
1213+ return assign(S);
1214+}
1215+
1216+bool
1217+SBuf::operator <(const SBuf &S) const
1218+{
1219+ return (cmp(S) < 0);
1220+}
1221+
1222+bool
1223+SBuf::operator >(const SBuf &S) const
1224+{
1225+ return (cmp(S) > 0);
1226+}
1227+
1228+bool
1229+SBuf::operator <=(const SBuf &S) const
1230+{
1231+ return (cmp(S) <= 0);
1232+}
1233+
1234+bool
1235+SBuf::operator >=(const SBuf &S) const
1236+{
1237+ return (cmp(S) >= 0);
1238+}
1239+
1240+SBuf::size_type
1241+SBuf::length() const
1242+{
1243+ return len_;
1244+}
1245+
1246+int
1247+SBuf::plength() const
1248+{
1249+ if (length() > INT_MAX)
1250+ throw SBufTooBigException(__FILE__, __LINE__);
1251+ return (int)length();
1252+}
1253+
1254+/**
1255+ * obtains a char* to the beginning of this SBuf in memory.
1256+ * \note the obtained string is NOT null-terminated.
1257+ */
1258+char *
1259+SBuf::buf() const
1260+{
1261+ return store_->mem+off_;
1262+}
1263+
1264+/** returns the pointer to the first char after this SBuf end
1265+ *
1266+ */
1267+char *
1268+SBuf::bufEnd() const
1269+{
1270+ return store_->mem+off_+len_;
1271+}
1272+
1273+/**
1274+ * Try to guesstimate how big a MemBlob to allocate.
1275+ * The result is guarranteed to be to be at least the desired
1276+ * size.
1277+ */
1278+const SBuf::size_type
1279+SBuf::estimateCapacity(SBuf::size_type desired) const
1280+{
1281+ return 2*desired;
1282+}
1283+
1284+/**
1285+ * To be called after having determined that the buffers are equal up to the
1286+ * length of the shortest one.
1287+ * If the buffers' length is the same, then they're equal. Otherwise, the
1288+ * longest one is deemed to be greater than the other.
1289+ * This matches the behavior of strcmp(1) and strcasecmp(1)
1290+ */
1291+int
1292+SBuf::commonCompareChecksPost(const SBuf &S) const
1293+{
1294+ if (length() == S.length()) //they're REALLY the same..
1295+ return 0;
1296+ if (length() > S.length())
1297+ return 1;
1298+ return -1;
1299+}
1300+
1301+/** obtain prototype store
1302+ *
1303+ * Just-created SBufs all share to the same MemBlob.
1304+ * This call instantiates and returns it.
1305+ */
1306+MemBlob::Pointer
1307+SBuf::GetStorePrototype()
1308+{
1309+ static MemBlob::Pointer InitialStore = NULL;
1310+ if (InitialStore == NULL) {
1311+ static char lowPrototype[] = "";
1312+ InitialStore = new MemBlob(lowPrototype, 0);
1313+ }
1314+ return InitialStore;
1315+}
1316+
1317+const char
1318+SBuf::operator [](SBuf::size_type pos) const
1319+{
1320+ ++stats.getChar;
1321+ if (pos < 0 || pos >= length())
1322+ return '\0';
1323+ return store_->mem[off_+pos];
1324+}
1325+
1326+const char
1327+SBuf::at(SBuf::size_type pos) const
1328+{
1329+ checkAccessBounds(pos);
1330+ return operator[](pos);
1331+}
1332+
1333+bool
1334+SBuf::isEmpty() const
1335+{
1336+ return (len_ == 0);
1337+}
1338
1339=== added file 'src/SBuf.h'
1340--- src/SBuf.h 1970-01-01 00:00:00 +0000
1341+++ src/SBuf.h 2013-07-04 15:56:30 +0000
1342@@ -0,0 +1,571 @@
1343+/*
1344+ * SBuf.h (C) 2008 Francesco Chemolli <kinkie@squid-cache.org>
1345+ *
1346+ * SQUID Web Proxy Cache http://www.squid-cache.org/
1347+ * ----------------------------------------------------------
1348+ *
1349+ * Squid is the result of efforts by numerous individuals from
1350+ * the Internet community; see the CONTRIBUTORS file for full
1351+ * details. Many organizations have provided support for Squid's
1352+ * development; see the SPONSORS file for full details. Squid is
1353+ * Copyrighted (C) 2001 by the Regents of the University of
1354+ * California; see the COPYRIGHT file for full details. Squid
1355+ * incorporates software developed and/or copyrighted by other
1356+ * sources; see the CREDITS file for full details.
1357+ *
1358+ * This program is free software; you can redistribute it and/or modify
1359+ * it under the terms of the GNU General Public License as published by
1360+ * the Free Software Foundation; either version 2 of the License, or
1361+ * (at your option) any later version.
1362+ *
1363+ * This program is distributed in the hope that it will be useful,
1364+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1365+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1366+ * GNU General Public License for more details.
1367+ *
1368+ * You should have received a copy of the GNU General Public License
1369+ * along with this program; if not, write to the Free Software
1370+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
1371+ */
1372+
1373+#ifndef SQUID_SBUF_H
1374+#define SQUID_SBUF_H
1375+
1376+#include "base/InstanceId.h"
1377+#include "Debug.h"
1378+#include "MemBlob.h"
1379+#include "SquidString.h"
1380+
1381+#if HAVE_UNISTD_H
1382+#include <unistd.h>
1383+#endif
1384+#if HAVE_STDARG_H
1385+#include <stdarg.h>
1386+#endif
1387+#if HAVE_IOSFWD
1388+#include <iosfwd>
1389+#endif
1390+
1391+/* squid string placeholder (for printf) */
1392+#ifndef SQUIDSBUFPH
1393+#define SQUIDSBUFPH "%.*s"
1394+#define SQUIDSBUFPRINT(s) (s).plength(),(s).rawContent()
1395+#endif /* SQUIDSBUFPH */
1396+
1397+typedef enum {
1398+ caseSensitive,
1399+ caseInsensitive
1400+} SBufCaseSensitive;
1401+
1402+/**
1403+ * Container for various SBuf class-wide statistics.
1404+ *
1405+ * The stats are not completely accurate; they're mostly meant to
1406+ * understand whether Squid is leaking resources
1407+ * and whether SBuf is paying off the expected gains.
1408+ */
1409+class SBufStats
1410+{
1411+public:
1412+ u_int64_t alloc; ///<number of calls to SBuf constructors
1413+ u_int64_t allocCopy; ///<number of calls to SBuf copy-constructor
1414+ u_int64_t allocFromString; ///<number of copy-allocations from Strings
1415+ u_int64_t allocFromCString; ///<number of copy-allocations from c-strings
1416+ u_int64_t assignFast; ///<number of no-copy assignment operations
1417+ u_int64_t clear; ///<number of clear operations
1418+ u_int64_t append; ///<number of append operations
1419+ u_int64_t toStream; ///<number of write operations to ostreams
1420+ u_int64_t setChar; ///<number of calls to setAt
1421+ u_int64_t getChar; ///<number of calls to at() and operator[]
1422+ u_int64_t compareSlow; ///<number of comparison operations requiring data scan
1423+ u_int64_t compareFast; ///<number of comparison operations not requiring data scan
1424+ u_int64_t copyOut; ///<number of data-copies to other forms of buffers
1425+ u_int64_t rawAccess; ///<number of accesses to raw contents
1426+ u_int64_t chop; ///<number of chop operations
1427+ u_int64_t trim; ///<number of trim operations
1428+ u_int64_t find; ///<number of find operations
1429+ u_int64_t scanf; ///<number of scanf operations
1430+ u_int64_t caseChange; ///<number of toUpper and toLower operations
1431+ u_int64_t cowFast; ///<number of cow operations not actually requiring a copy
1432+ u_int64_t cowSlow; ///<number of cow operations requiring a copy
1433+ u_int64_t live; ///<number of currently-allocated SBuf
1434+
1435+ /**
1436+ * Dump statistics to an ostream.
1437+ */
1438+ std::ostream& dump(std::ostream &os) const;
1439+ SBufStats();
1440+
1441+ SBufStats& operator +=(const SBufStats&);
1442+};
1443+
1444+/**
1445+ * A String or Buffer.
1446+ * Features: refcounted backing store, cheap copy and sub-stringing
1447+ * operations, copy-on-write to isolate change operations to each instance.
1448+ * Where possible, we're trying to mimic std::string's interface.
1449+ */
1450+class SBuf
1451+{
1452+public:
1453+ typedef int32_t size_type;
1454+ static const size_type npos = -1;
1455+
1456+ /// Maximum size of a SBuf. By design it MUST be < MAX(size_type)/2. Currently 256Mb.
1457+ static const size_type maxSize = 0xfffffff;
1458+
1459+ /// create an empty (zero-size) SBuf
1460+ SBuf();
1461+ SBuf(const SBuf &S);
1462+
1463+ /** Constructor: import c-style string
1464+ *
1465+ * Create a new SBuf containing a COPY of the contents of the
1466+ * c-string
1467+ * \param S the c string to be copied
1468+ * \param pos how many bytes to skip at the beginning of the c-string
1469+ * \param n how many bytes to import into the SBuf. If it is SBuf::npos
1470+ * or unspecified, imports to end-of-cstring
1471+ * \note it is the caller's responsibility not to go out of bounds
1472+ * \note bounds is 0 <= pos < length()
1473+ */
1474+ explicit SBuf(const char *S, size_type pos = 0, size_type n = npos);
1475+
1476+ /** Constructor: import SquidString, copying contents.
1477+ *
1478+ * This method will be removed once SquidString has gone.
1479+ */
1480+ SBuf(const String &S);
1481+
1482+ ~SBuf();
1483+ /** Explicit assignment.
1484+ *
1485+ * Current SBuf will share backing store with the assigned one.
1486+ */
1487+ SBuf& assign(const SBuf &S);
1488+ /** Assignment operator.
1489+ *
1490+ * Current SBuf will share backing store with the assigned one.
1491+ */
1492+ _SQUID_INLINE_ SBuf& operator =(const SBuf & S);
1493+
1494+ /** Import a c-string into a SBuf, copying the data.
1495+ *
1496+ * It is the caller's duty to free the imported string, if needed.
1497+ * \param S the c string to be copied
1498+ * \param pos how many bytes to skip at the beginning of the c-string.
1499+ * \param n how many bytes to import into the SBuf. If it is SBuf::npos
1500+ * or unspecified, imports to end-of-cstring
1501+ * \note it is the caller's responsibility not to go out of bounds
1502+ * \note bounds is 0 <= pos < length()
1503+ */
1504+ SBuf& assign(const char *S, size_type pos = 0, size_type n = npos);
1505+
1506+ /** Assignment operator. Copy a NULL-terminated c-style string into a SBuf.
1507+ *
1508+ * Copy a c-style string into a SBuf. Shortcut for SBuf.assign(S)
1509+ * It is the caller's duty to free the imported string, if needed.
1510+ */
1511+ _SQUID_INLINE_ SBuf& operator =(const char *S);
1512+
1513+ /** Import a std::string into a SBuf. Contents are copied.
1514+ *
1515+ * \param pos skip this many bytes at the beginning of string.
1516+ * 0 is beginning-of-string
1517+ * \param n how many bytes to copy. Default is SBuf::npos, end-of-string.
1518+ */
1519+ SBuf& assign(const std::string &s, size_type pos = 0, size_type n = npos);
1520+
1521+ /** reset the SBuf as if it was just created.
1522+ *
1523+ * Resets the SBuf to empty, memory is freed lazily.
1524+ */
1525+ void clear();
1526+
1527+ /** Append operation
1528+ *
1529+ * Append the supplied SBuf to the current one; extend storage as needed.
1530+ */
1531+ SBuf& append(const SBuf & S);
1532+
1533+ /** Append operation for C-style strings.
1534+ *
1535+ * Append the supplied c-string to the SBuf; extend storage
1536+ * as needed.
1537+ *
1538+ * \param S the c string to be copied. Can be NULL.
1539+ * \param pos how many bytes to skip at the beginning of the c-string
1540+ * \param n how many bytes to import into the SBuf. If it is SBuf::npos
1541+ * or unspecified, imports to end-of-cstring
1542+ */
1543+ SBuf& append(const char * S, size_type pos = 0, size_type n = npos);
1544+
1545+ /** Append operation for std::string
1546+ *
1547+ * Append the supplied std::string to the SBuf; extend storage as needed.
1548+ *
1549+ * \param string the std::string to be copied.
1550+ * \param pos how many bytes to skip at the beginning of the c-string
1551+ * \param n how many bytes to import into the SBuf. If it is SBuf::npos
1552+ * or unspecified, imports to end-of-cstring
1553+ */
1554+ SBuf& append(const std::string &str, size_type pos = 0, size_type n = npos);
1555+
1556+ /** Assignment operation with printf(3)-style definition
1557+ * \note arguments may be evaluated more than once, be careful
1558+ * of side-effects
1559+ */
1560+ SBuf& Printf(const char *fmt, ...);
1561+
1562+ /** Append operation with printf-style arguments
1563+ * \note arguments may be evaluated more than once, be careful
1564+ * of side-effects
1565+ */
1566+ SBuf& appendf(const char *fmt, ...);
1567+ /** Append operation, with vsprintf(3)-style arguments.
1568+ * \note arguments may be evaluated more than once, be careful
1569+ * of side-effects
1570+ */
1571+ SBuf& vappendf(const char *fmt, va_list vargs);
1572+
1573+ /** print a SBuf.
1574+ */
1575+ std::ostream& print(std::ostream &os) const;
1576+
1577+ /** print the sbuf, debug information and stats
1578+ *
1579+ * Debug function, dumps to a stream informations on the current SBuf,
1580+ * including low-level details and statistics.
1581+ */
1582+ std::ostream& dump(std::ostream &os) const;
1583+
1584+ /** random-access read to any char within the SBuf
1585+ *
1586+ * does not check access bounds. If you need that, use at()
1587+ */
1588+ _SQUID_INLINE_ const char operator [](size_type pos) const;
1589+
1590+ /** random-access read to any char within the SBuf.
1591+ *
1592+ * \throw OutOfBoundsException when access is out of bounds
1593+ * \note bounds is 0 <= pos < length()
1594+ */
1595+ _SQUID_INLINE_ const char at(size_type pos) const;
1596+
1597+ /** direct-access set a byte at a specified operation.
1598+ *
1599+ * \param pos the position to be overwritten
1600+ * \param toset the value to be written
1601+ * \throw OutOfBoundsException when pos is of bounds
1602+ * \note bounds is 0 <= pos < length()
1603+ * \note performs a copy-on-write if needed.
1604+ */
1605+ void setAt(size_type pos, char toset);
1606+
1607+ /** compare to other SBuf, str(case)cmp-style
1608+ *
1609+ * \param isCaseSensitive one of caseSensitive or caseInsensitive
1610+ * \param n compare up to this many bytes. if npos (default), compare whole SBufs
1611+ * \retval >0 argument of the call is greater than called SBuf
1612+ * \retval <0 argument of the call is smaller than called SBuf
1613+ * \retval 0 argument of the call has the same contents of called SBuf
1614+ */
1615+ int compare(const SBuf &S, SBufCaseSensitive isCaseSensitive, size_type n = npos) const;
1616+
1617+ /// shorthand version for compare
1618+ inline int cmp(const SBuf &S, size_type n = npos) const {
1619+ return compare(S,caseSensitive,n);
1620+ }
1621+
1622+ /// shorthand version for case-insensitive comparison
1623+ inline int casecmp(const SBuf &S, size_type n = npos) const {
1624+ return compare(S,caseInsensitive,n);
1625+ }
1626+
1627+ /** check whether the entire supplied argument is a prefix of the SBuf.
1628+ * \param S the prefix to match against
1629+ * \param isCaseSensitive one of caseSensitive or caseInsensitive
1630+ * \retval true argument is a prefix of the SBuf
1631+ */
1632+ bool startsWith(const SBuf &S, SBufCaseSensitive isCaseSensitive = caseSensitive) const;
1633+
1634+ /** equality check
1635+ */
1636+ bool operator ==(const SBuf & S) const;
1637+ bool operator !=(const SBuf & S) const;
1638+ _SQUID_INLINE_ bool operator <(const SBuf &S) const;
1639+ _SQUID_INLINE_ bool operator >(const SBuf &S) const;
1640+ _SQUID_INLINE_ bool operator <=(const SBuf &S) const;
1641+ _SQUID_INLINE_ bool operator >=(const SBuf &S) const;
1642+
1643+ /** Consume bytes at the head of the SBuf
1644+ *
1645+ * Consume N chars at SBuf head, or to SBuf's end,
1646+ * whichever is shorter. If more bytes are consumed than available,
1647+ * the SBuf is emptied
1648+ * \param n how many bytes to remove; could be zero.
1649+ * SBuf::npos (or no argument) means 'to the end of SBuf'
1650+ * \return a new SBuf containing the consumed bytes.
1651+ */
1652+ SBuf consume(size_type n = npos);
1653+
1654+ /** gets global statistic informations
1655+ *
1656+ */
1657+ static const SBufStats& GetStats();
1658+
1659+ /** Copy SBuf contents into user-supplied C buffer.
1660+ *
1661+ * Export a copy of the SBuf's contents into the user-supplied
1662+ * buffer, up to the user-supplied-length. No zero-termination is performed
1663+ * \return num the number of actually-copied chars.
1664+ */
1665+ size_type copy(char *dest, size_type n) const;
1666+
1667+ /** exports a pointer to the SBuf internal storage.
1668+ * \warning ACCESSING RAW STORAGE IS DANGEROUS!
1669+ *
1670+ * Returns a pointer to SBuf's content. No terminating null character
1671+ * is appended (use c_str() for that).
1672+ * The returned value points to an internal location whose contents
1673+ * are guaranteed to remain unchanged only until the next call
1674+ * to a non-constant member function of the SBuf object. Such a
1675+ * call may be implicit (e.g., when SBuf is destroyed
1676+ * upon leaving the current context).
1677+ * This is a very UNSAFE way of accessing the data.
1678+ * This call never returns NULL.
1679+ * \see c_str
1680+ * \note the memory management system guarantees that the exported region
1681+ * of memory will remain valid if the caller keeps holding
1682+ * a valid reference to the SBuf object and does not write or append to
1683+ * it. For example:
1684+ * \code
1685+ * SBuf foo("some string");
1686+ * const char *bar = foo.rawContent();
1687+ * doSomething(bar); //safe
1688+ * foo.append(" other string");
1689+ * doSomething(bar); //unsafe
1690+ * \endcode
1691+ */
1692+ const char* rawContent() const;
1693+
1694+ /** Exports a writable pointer to the SBuf internal storage.
1695+ * \warning Use with EXTREME caution, this is a dangerous operation.
1696+ *
1697+ * Returns a pointer to the first unused byte in the SBuf's storage,
1698+ * to be used for writing. If minsize is specified, it is guaranteed
1699+ * that at least minsize bytes will be available for writing. Otherwise
1700+ * it is guaranteed that at least as much storage as is currently
1701+ * available will be available for the call. A COW will be performed
1702+ * if necessary to ensure that a following write will not trample
1703+ * a shared MemBlob. The returned pointer must not be stored, and will
1704+ * become invalid at the first call to a non-const method call
1705+ * on the SBuf.
1706+ * This call guarantees to never return NULL
1707+ * This call always forces a cow()
1708+ * \throw SBufTooBigException if the user tries to allocate too big a SBuf
1709+ */
1710+ char *rawSpace(size_type minSize = npos);
1711+
1712+ /** Force a SBuf's size
1713+ * \warning use with EXTREME caution, this is a dangerous operation
1714+ *
1715+ * Adapt the SBuf internal state after external interference
1716+ * such as writing into it via rawSpace.
1717+ * \throw TextException if SBuf doesn't have exclusive ownership of store
1718+ * \throw SBufTooBigException if new size is bigger than available store space
1719+ */
1720+ void forceSize(size_type newSize);
1721+
1722+ /** exports a null-terminated reference to the SBuf internal storage.
1723+ * \warning ACCESSING RAW STORAGE IS DANGEROUS! DO NOT EVER USE
1724+ * THE RETURNED POINTER FOR WRITING
1725+ *
1726+ * The returned value points to an internal location whose contents
1727+ * are guaranteed to remain unchanged only until the next call
1728+ * to a non-constant member function of the SBuf object. Such a
1729+ * call may be implicit (e.g., when SBuf is destroyed
1730+ * upon leaving the current context).
1731+ * This is a very UNSAFE way of accessing the data.
1732+ * This call never returns NULL.
1733+ * \see rawContent
1734+ * \note the memory management system guarantees that the exported region
1735+ * of memory will remain valid if the caller keeps holding
1736+ * a valid reference to the SBuf object and does not write or append to
1737+ * it
1738+ */
1739+ const char* c_str();
1740+
1741+ /** Returns the number of bytes stored in SBuf.
1742+ */
1743+ _SQUID_INLINE_ size_type length() const;
1744+
1745+ /** Get the length of the SBuf, as a signed integer
1746+ *
1747+ * Compatibility function for printf(3) which requires a signed int
1748+ * \throw SBufTooBigException if the SBuf is too big for a signed integer
1749+ */
1750+ _SQUID_INLINE_ int plength() const;
1751+
1752+ /** Check whether the SBuf is empty
1753+ *
1754+ * \return true if length() == 0
1755+ */
1756+ _SQUID_INLINE_ bool isEmpty() const;
1757+
1758+ /** Request to extend the SBuf's free store space.
1759+ *
1760+ * After the reserveSpace request, the SBuf is guaranteed to have at
1761+ * least minSpace bytes of append-able backing store (on top of the
1762+ * currently-used portion).
1763+ * \throw SBufTooBigException if the user tries to allocate too big a SBuf
1764+ */
1765+ void reserveSpace(size_type minSpace);
1766+
1767+ /** Request to resize the SBuf's store
1768+ *
1769+ * After this method is called, the SBuf is guaranteed to have at least
1770+ * minCapcity bytes of total space, including the currently-used portion
1771+ * \throw SBufTooBigException if the user tries to allocate too big a SBuf
1772+ */
1773+ void reserveCapacity(size_type minCapacity);
1774+
1775+ /** slicing method
1776+ *
1777+ * Removes SBuf prefix and suffix, leaving a sequence of <i>n</i>
1778+ * bytes starting from position <i>pos</i> first byte is at pos 0.
1779+ * \param pos start sub-stringing from this byte. If it is
1780+ * greater than the SBuf length, the SBuf is emptied and
1781+ * an empty SBuf is returned
1782+ * \param n maximum number of bytes of the resulting SBuf.
1783+ * SBuf::npos means "to end of SBuf".
1784+ * if 0 returns an empty SBuf.
1785+ */
1786+ SBuf& chop(size_type pos, size_type n = npos);
1787+
1788+ /** Remove characters in the toremove set at the beginning, end or both
1789+ *
1790+ * \param toremove characters to be removed. Stops chomping at the first
1791+ * found char not in the set
1792+ * \param atBeginning if true (default), strips at the beginning of the SBuf
1793+ * \param atEnd if true (default), strips at the end of the SBuf
1794+ */
1795+ SBuf& trim(const SBuf &toRemove, bool atBeginning = true, bool atEnd = true);
1796+
1797+ /** Extract a part of the current SBuf.
1798+ *
1799+ * Return a fresh a fresh copy of a portion the current SBuf, which is left untouched.
1800+ * \see trim
1801+ */
1802+ SBuf substr(size_type pos, size_type n = npos) const;
1803+
1804+ /** Find first occurrence of character in SBuf
1805+ *
1806+ * Returns the index in the SBuf of the first occurrence of char c.
1807+ * \param startPos if specified, ignore any occurrences before that position
1808+ * if startPos is npos, always return npos
1809+ * \return SBuf::npos if the char was not found
1810+ */
1811+ size_type find(char c, size_type startPos = 0) const;
1812+
1813+ /** Find first occurrence of SBuf in SBuf.
1814+ *
1815+ * Returns the index in the SBuf of the first occurrence of the
1816+ * sequence contained in the str argument.
1817+ * \param startPos if specified, ignore any occurrences before that position
1818+ * if startPos is npos, always return npos
1819+ * \return SBuf::npos if the SBuf was not found
1820+ */
1821+ size_type find(const SBuf & str, size_type startPos = 0) const;
1822+
1823+ /** Find last occurrence of character in SBuf
1824+ *
1825+ * Returns the index in the SBuf of the last occurrence of char c.
1826+ * \param endPos if specified, ignore any occurrences after that position
1827+ * \return SBuf::npos if the char was not found
1828+ */
1829+ size_type rfind(char c, size_type endPos = npos) const;
1830+
1831+ /** Find last occurrence of SBuf in SBuf
1832+ *
1833+ * Returns the index in the SBuf of the last occurrence of the
1834+ * sequence contained in the str argument.
1835+ * \return SBuf::npos if the sequence was not found
1836+ * \param endPos if specified, ignore any occurrences after that position
1837+ */
1838+ size_type rfind(const SBuf &str, size_type endPos = npos) const;
1839+
1840+ /** Find first occurrence of character of set in SBuf
1841+ *
1842+ * Finds the first occurrence of ANY of the characters in the supplied set in
1843+ * the SBuf.
1844+ * \return SBuf::npos if no character in the set could be found
1845+ * \param startPos if specified, ignore any occurrences before that position
1846+ */
1847+ size_type find_first_of(const SBuf &set, size_type startPos = 0) const;
1848+
1849+ /** sscanf-alike
1850+ *
1851+ * sscanf re-implementation. Non-const, and not \0-clean.
1852+ * \return same as sscanf
1853+ * \see man sscanf(3)
1854+ */
1855+ int scanf(const char *format, ...);
1856+
1857+ /** Lower-case SBuf
1858+ *
1859+ * Returns a lower-cased COPY of the SBuf
1860+ * \see man tolower(3)
1861+ */
1862+ SBuf toLower() const;
1863+
1864+ /** Upper-case SBuf
1865+ *
1866+ * Returns an upper-cased COPY of the SBuf
1867+ * \see man toupper(3)
1868+ */
1869+ SBuf toUpper() const;
1870+
1871+ /** String export function
1872+ * converts the SBuf to a legacy String, by copy. Transitional.
1873+ */
1874+ String toString() const;
1875+
1876+ /// TODO: possibly implement erase() similar to std::string's erase
1877+ /// TODO: possibly implement a replace() call
1878+private:
1879+
1880+ MemBlob::Pointer store_; ///< memory block, possibly shared with other SBufs
1881+ size_type off_; ///< our content start offset from the beginning of shared store_
1882+ size_type len_; ///< number of our content bytes in shared store_
1883+ static SBufStats stats; ///< class-wide statistics
1884+
1885+ /// SBuf object identifier; does not change when contents do,
1886+ /// including during assignment
1887+ const InstanceId<SBuf> id;
1888+
1889+ _SQUID_INLINE_ static MemBlob::Pointer GetStorePrototype();
1890+
1891+ _SQUID_INLINE_ char * buf() const;
1892+ _SQUID_INLINE_ char * bufEnd() const;
1893+ _SQUID_INLINE_ const size_type estimateCapacity(size_type desired) const;
1894+ void reAlloc(size_type newsize);
1895+
1896+ bool cow(size_type minsize = npos);
1897+
1898+ void checkAccessBounds(size_type pos) const;
1899+ _SQUID_INLINE_ int commonCompareChecksPre(const SBuf &S) const;
1900+ _SQUID_INLINE_ int commonCompareChecksPost(const SBuf &S) const;
1901+
1902+};
1903+
1904+/**
1905+ * Prints a SBuf to the supplied stream, allowing for chaining
1906+ */
1907+std::ostream& operator <<(std::ostream &os, const SBuf &S);
1908+
1909+#if _USE_INLINE_
1910+#include "SBuf.cci"
1911+#endif
1912+
1913+#endif /* SQUID_SBUF_H */
1914
1915=== added file 'src/SBufExceptions.cc'
1916--- src/SBufExceptions.cc 1970-01-01 00:00:00 +0000
1917+++ src/SBufExceptions.cc 2013-07-04 15:56:30 +0000
1918@@ -0,0 +1,72 @@
1919+/*
1920+ * SBufExceptions.cc (C) 2008 Francesco Chemolli <kinkie@squid-cache.org>
1921+ *
1922+ * SQUID Web Proxy Cache http://www.squid-cache.org/
1923+ * ----------------------------------------------------------
1924+ *
1925+ * Squid is the result of efforts by numerous individuals from
1926+ * the Internet community; see the CONTRIBUTORS file for full
1927+ * details. Many organizations have provided support for Squid's
1928+ * development; see the SPONSORS file for full details. Squid is
1929+ * Copyrighted (C) 2001 by the Regents of the University of
1930+ * California; see the COPYRIGHT file for full details. Squid
1931+ * incorporates software developed and/or copyrighted by other
1932+ * sources; see the CREDITS file for full details.
1933+ *
1934+ * This program is free software; you can redistribute it and/or modify
1935+ * it under the terms of the GNU General Public License as published by
1936+ * the Free Software Foundation; either version 2 of the License, or
1937+ * (at your option) any later version.
1938+ *
1939+ * This program is distributed in the hope that it will be useful,
1940+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1941+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1942+ * GNU General Public License for more details.
1943+ *
1944+ * You should have received a copy of the GNU General Public License
1945+ * along with this program; if not, write to the Free Software
1946+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
1947+ */
1948+
1949+#include "squid.h"
1950+#include "OutOfBoundsException.h"
1951+#include "SBuf.h"
1952+#include "SBufExceptions.h"
1953+
1954+// Note: the SBuf is intentionally passed by copy rather than reference,
1955+// to let refcounting act.
1956+OutOfBoundsException::OutOfBoundsException(const SBuf &throwingBuf,
1957+ SBuf::size_type &pos,
1958+ const char *aFileName, int aLineNo)
1959+ :TextException(NULL, aFileName, aLineNo)
1960+{
1961+ _buf = throwingBuf;
1962+ _pos = pos;
1963+ SBuf explanatoryText("OutOfBoundsException");
1964+ if (aLineNo != -1)
1965+ explanatoryText.appendf(" at line %d", aLineNo);
1966+ if (aFileName != 0)
1967+ explanatoryText.appendf(" in file %s", aFileName);
1968+ explanatoryText.appendf(" while accessing position %d in a SBuf long %d",
1969+ pos, throwingBuf.length());
1970+ // we can safely alias c_str as both are local to the object
1971+ // and will not further manipulated.
1972+ message = xstrndup(explanatoryText.c_str(),explanatoryText.length());
1973+}
1974+
1975+OutOfBoundsException::~OutOfBoundsException() throw()
1976+{ }
1977+
1978+NullSBufException::NullSBufException(const char *aFilename, int aLineNo)
1979+ : TextException("Trying to access a null SBuf", aFilename, aLineNo)
1980+{ }
1981+
1982+InvalidParamException::InvalidParamException(const char *aFilename, int aLineNo)
1983+ : TextException("Invalid parameter", aFilename, aLineNo)
1984+{ }
1985+
1986+SBufTooBigException::SBufTooBigException(const char *aFilename, int aLineNo)
1987+ : TextException("Trying to create an oversize SBuf", aFilename, aLineNo)
1988+{ }
1989+
1990+/* */
1991
1992=== added file 'src/SBufExceptions.h'
1993--- src/SBufExceptions.h 1970-01-01 00:00:00 +0000
1994+++ src/SBufExceptions.h 2013-07-04 15:56:30 +0000
1995@@ -0,0 +1,65 @@
1996+/*
1997+ * SBufExceptions.h (C) 2008 Francesco Chemolli <kinkie@squid-cache.org>
1998+ *
1999+ * SQUID Web Proxy Cache http://www.squid-cache.org/
2000+ * ----------------------------------------------------------
2001+ *
2002+ * Squid is the result of efforts by numerous individuals from
2003+ * the Internet community; see the CONTRIBUTORS file for full
2004+ * details. Many organizations have provided support for Squid's
2005+ * development; see the SPONSORS file for full details. Squid is
2006+ * Copyrighted (C) 2001 by the Regents of the University of
2007+ * California; see the COPYRIGHT file for full details. Squid
2008+ * incorporates software developed and/or copyrighted by other
2009+ * sources; see the CREDITS file for full details.
2010+ *
2011+ * This program is free software; you can redistribute it and/or modify
2012+ * it under the terms of the GNU General Public License as published by
2013+ * the Free Software Foundation; either version 2 of the License, or
2014+ * (at your option) any later version.
2015+ *
2016+ * This program is distributed in the hope that it will be useful,
2017+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2018+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2019+ * GNU General Public License for more details.
2020+ *
2021+ * You should have received a copy of the GNU General Public License
2022+ * along with this program; if not, write to the Free Software
2023+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
2024+ */
2025+
2026+#ifndef SQUID_SBUFEXCEPTIONS_H
2027+#define SQUID_SBUFEXCEPTIONS_H
2028+
2029+#include "base/TextException.h"
2030+
2031+/**
2032+ * Exception raised when the user is trying to operate on a Null SBuf
2033+ * \todo move to an Exceptions.h?
2034+ */
2035+class NullSBufException : public TextException
2036+{
2037+public:
2038+ explicit NullSBufException(const char *aFilename = 0, int aLineNo = -1);
2039+};
2040+
2041+/**
2042+ * Exception raised when call parameters are not valid
2043+ * \todo move to an Exceptions.h?
2044+ */
2045+class InvalidParamException : public TextException
2046+{
2047+public:
2048+ explicit InvalidParamException(const char *aFilename = 0, int aLineNo = -1);
2049+};
2050+
2051+/**
2052+ * Exception raised when an attempt to resize a SBuf would cause it to reserve too big
2053+ */
2054+class SBufTooBigException : public TextException
2055+{
2056+public:
2057+ explicit SBufTooBigException(const char *aFilename = 0, int aLineNo = -1);
2058+};
2059+
2060+#endif /* SQUID_SBUFEXCEPTIONS_H */
2061
2062=== added file 'src/SBufExtras.cc'
2063--- src/SBufExtras.cc 1970-01-01 00:00:00 +0000
2064+++ src/SBufExtras.cc 2013-07-04 15:56:30 +0000
2065@@ -0,0 +1,104 @@
2066+/*
2067+ * SBufExtras.h (C) 2008 Francesco Chemolli <kinkie@squid-cache.org>
2068+ *
2069+ * SQUID Web Proxy Cache http://www.squid-cache.org/
2070+ * ----------------------------------------------------------
2071+ *
2072+ * Squid is the result of efforts by numerous individuals from
2073+ * the Internet community; see the CONTRIBUTORS file for full
2074+ * details. Many organizations have provided support for Squid's
2075+ * development; see the SPONSORS file for full details. Squid is
2076+ * Copyrighted (C) 2001 by the Regents of the University of
2077+ * California; see the COPYRIGHT file for full details. Squid
2078+ * incorporates software developed and/or copyrighted by other
2079+ * sources; see the CREDITS file for full details.
2080+ *
2081+ * This program is free software; you can redistribute it and/or modify
2082+ * it under the terms of the GNU General Public License as published by
2083+ * the Free Software Foundation; either version 2 of the License, or
2084+ * (at your option) any later version.
2085+ *
2086+ * This program is distributed in the hope that it will be useful,
2087+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2088+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2089+ * GNU General Public License for more details.
2090+ *
2091+ * You should have received a copy of the GNU General Public License
2092+ * along with this program; if not, write to the Free Software
2093+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
2094+ */
2095+
2096+/*
2097+ * This file contains various helper functions which are meant to be
2098+ * a bridge towards SBuf integration, but which do not belong to SBuf proper,
2099+ * such as functions shuttling to and from other data types.
2100+ */
2101+
2102+#include "squid.h"
2103+#include "ipc/Messages.h"
2104+#include "ipc/TypedMsgHdr.h"
2105+#include "mgr/Registration.h"
2106+#include "SBufExtras.h"
2107+#include "StoreEntryStream.h"
2108+
2109+SBufStatsAction::SBufStatsAction(const Mgr::CommandPointer &cmd_):
2110+ Action(cmd_)
2111+{ } //default constructor is OK for data member
2112+
2113+SBufStatsAction::Pointer
2114+SBufStatsAction::Create(const Mgr::CommandPointer &cmd)
2115+{
2116+ debugs(24, 8, "" );
2117+ return new SBufStatsAction(cmd);
2118+}
2119+void
2120+SBufStatsAction::add(const Mgr::Action& action)
2121+{
2122+ debugs(24, 8, "");
2123+ data.sbdata += dynamic_cast<const SBufStatsAction&>(action).data.sbdata;
2124+ data.mbdata += dynamic_cast<const SBufStatsAction&>(action).data.mbdata;
2125+}
2126+
2127+void
2128+SBufStatsAction::collect()
2129+{
2130+ debugs(24, 8, "" );
2131+ data.sbdata = SBuf::GetStats();
2132+ data.mbdata = MemBlob::GetStats();
2133+}
2134+
2135+void
2136+SBufStatsAction::dump(StoreEntry* entry)
2137+{
2138+ debugs(24, 8, "" );
2139+ Must(entry != NULL);
2140+ StoreEntryStream ses(entry);
2141+ data.sbdata.dump(ses);
2142+ data.mbdata.dump(ses);
2143+}
2144+
2145+void
2146+SBufStatsAction::pack(Ipc::TypedMsgHdr& msg) const
2147+{
2148+ debugs(24, 8, "" );
2149+ msg.setType(Ipc::mtCacheMgrResponse);
2150+ msg.putPod(data);
2151+}
2152+
2153+void
2154+SBufStatsAction::unpack(const Ipc::TypedMsgHdr& msg)
2155+{
2156+ debugs(24, 8, "" );
2157+ msg.checkType(Ipc::mtCacheMgrResponse);
2158+ msg.getPod(data);
2159+}
2160+
2161+class SBufStatsRegistrationHelperObject
2162+{
2163+public:
2164+ SBufStatsRegistrationHelperObject() {
2165+ Mgr::RegisterAction("sbuf", "String-Buffer statistics",
2166+ &SBufStatsAction::Create, 0 , 1);
2167+ }
2168+};
2169+static SBufStatsRegistrationHelperObject sbufstatsinstantiator;
2170
2171=== added file 'src/SBufExtras.h'
2172--- src/SBufExtras.h 1970-01-01 00:00:00 +0000
2173+++ src/SBufExtras.h 2013-07-04 15:56:30 +0000
2174@@ -0,0 +1,66 @@
2175+/*
2176+ * SBufExtras.h (C) 2008 Francesco Chemolli <kinkie@squid-cache.org>
2177+ *
2178+ * SQUID Web Proxy Cache http://www.squid-cache.org/
2179+ * ----------------------------------------------------------
2180+ *
2181+ * Squid is the result of efforts by numerous individuals from
2182+ * the Internet community; see the CONTRIBUTORS file for full
2183+ * details. Many organizations have provided support for Squid's
2184+ * development; see the SPONSORS file for full details. Squid is
2185+ * Copyrighted (C) 2001 by the Regents of the University of
2186+ * California; see the COPYRIGHT file for full details. Squid
2187+ * incorporates software developed and/or copyrighted by other
2188+ * sources; see the CREDITS file for full details.
2189+ *
2190+ * This program is free software; you can redistribute it and/or modify
2191+ * it under the terms of the GNU General Public License as published by
2192+ * the Free Software Foundation; either version 2 of the License, or
2193+ * (at your option) any later version.
2194+ *
2195+ * This program is distributed in the hope that it will be useful,
2196+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2197+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2198+ * GNU General Public License for more details.
2199+ *
2200+ * You should have received a copy of the GNU General Public License
2201+ * along with this program; if not, write to the Free Software
2202+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
2203+ */
2204+
2205+/*
2206+ * This file contains various helper functions which are meant to be
2207+ * a bridge towards SBuf integration, but which do not belong to SBuf proper,
2208+ * such as functions shuttling to and from other data types.
2209+ */
2210+
2211+#ifndef SQUID_SBUFEXTRAS_H
2212+#define SQUID_SBUFEXTRAS_H
2213+
2214+#include "ipc/TypedMsgHdr.h"
2215+#include "MemBuf.h"
2216+#include "mgr/Action.h"
2217+#include "SBuf.h"
2218+#include "Store.h"
2219+
2220+class SBufStatsAction: public Mgr::Action
2221+{
2222+protected:
2223+ SBufStatsAction(const Mgr::CommandPointer &cmd);
2224+ virtual void collect();
2225+ virtual void dump(StoreEntry* entry);
2226+
2227+public:
2228+ static Pointer Create(const Mgr::CommandPointer &cmd);
2229+ virtual void add(const Mgr::Action& action);
2230+ virtual void pack(Ipc::TypedMsgHdr& msg) const;
2231+ virtual void unpack(const Ipc::TypedMsgHdr& msg);
2232+
2233+private:
2234+ struct SbufStatsActionData {
2235+ SBufStats sbdata;
2236+ MemBlobStats mbdata;
2237+ } data;
2238+};
2239+
2240+#endif /* SQUID_SBUFEXTRAS_H */
2241
2242=== added file 'src/SBufList.cc'
2243--- src/SBufList.cc 1970-01-01 00:00:00 +0000
2244+++ src/SBufList.cc 2013-07-04 15:56:30 +0000
2245@@ -0,0 +1,56 @@
2246+/*
2247+ * SBufList.cc (C) 2009 Francesco Chemolli <kinkie@squid-cache.org>
2248+ *
2249+ * SQUID Web Proxy Cache http://www.squid-cache.org/
2250+ * ----------------------------------------------------------
2251+ *
2252+ * Squid is the result of efforts by numerous individuals from
2253+ * the Internet community; see the CONTRIBUTORS file for full
2254+ * details. Many organizations have provided support for Squid's
2255+ * development; see the SPONSORS file for full details. Squid is
2256+ * Copyrighted (C) 2001 by the Regents of the University of
2257+ * California; see the COPYRIGHT file for full details. Squid
2258+ * incorporates software developed and/or copyrighted by other
2259+ * sources; see the CREDITS file for full details.
2260+ *
2261+ * This program is free software; you can redistribute it and/or modify
2262+ * it under the terms of the GNU General Public License as published by
2263+ * the Free Software Foundation; either version 2 of the License, or
2264+ * (at your option) any later version.
2265+ *
2266+ * This program is distributed in the hope that it will be useful,
2267+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2268+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2269+ * GNU General Public License for more details.
2270+ *
2271+ * You should have received a copy of the GNU General Public License
2272+ * along with this program; if not, write to the Free Software
2273+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
2274+ */
2275+
2276+#include "squid.h"
2277+#include "SBufList.h"
2278+
2279+SBufList& SBufList::add(SBuf S)
2280+{
2281+ push_back(S);
2282+ return *this;
2283+}
2284+
2285+bool SBufList::isMember(const SBuf &S, SBufCaseSensitive case_sensitive)
2286+{
2287+ iterator i;
2288+ for (i = begin(); i != end(); ++i)
2289+ if (i->compare(S,case_sensitive) == 0)
2290+ return true;
2291+ return false;
2292+}
2293+
2294+bool SBufList::isPrefix(const SBuf &s, SBufCaseSensitive case_sensitive)
2295+{
2296+ iterator i;
2297+ for (i = begin(); i != end(); ++i)
2298+ if (i->startsWith(s,case_sensitive))
2299+ return true;
2300+ return false;
2301+}
2302
2303=== added file 'src/SBufList.h'
2304--- src/SBufList.h 1970-01-01 00:00:00 +0000
2305+++ src/SBufList.h 2013-07-04 15:56:30 +0000
2306@@ -0,0 +1,62 @@
2307+/*
2308+ * SBufList.h (C) 2009 Francesco Chemolli <kinkie@squid-cache.org>
2309+ *
2310+ * SQUID Web Proxy Cache http://www.squid-cache.org/
2311+ * ----------------------------------------------------------
2312+ *
2313+ * Squid is the result of efforts by numerous individuals from
2314+ * the Internet community; see the CONTRIBUTORS file for full
2315+ * details. Many organizations have provided support for Squid's
2316+ * development; see the SPONSORS file for full details. Squid is
2317+ * Copyrighted (C) 2001 by the Regents of the University of
2318+ * California; see the COPYRIGHT file for full details. Squid
2319+ * incorporates software developed and/or copyrighted by other
2320+ * sources; see the CREDITS file for full details.
2321+ *
2322+ * This program is free software; you can redistribute it and/or modify
2323+ * it under the terms of the GNU General Public License as published by
2324+ * the Free Software Foundation; either version 2 of the License, or
2325+ * (at your option) any later version.
2326+ *
2327+ * This program is distributed in the hope that it will be useful,
2328+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2329+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2330+ * GNU General Public License for more details.
2331+ *
2332+ * You should have received a copy of the GNU General Public License
2333+ * along with this program; if not, write to the Free Software
2334+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
2335+ */
2336+
2337+#ifndef SQUID_SBUFLIST_H
2338+#define SQUID_SBUFLIST_H
2339+
2340+#include "SBuf.h"
2341+#include <list>
2342+
2343+/** List of SBuf
2344+ *
2345+ */
2346+class SBufList : public std::list<SBuf>
2347+{
2348+public:
2349+ /** Add a SBuf to the list
2350+ *
2351+ * \note can be chained
2352+ */
2353+ SBufList& add(SBuf);
2354+
2355+ /** check for membership
2356+ *
2357+ * true if the supplied SBuf is a member of the list
2358+ * \param case_sensitive one of caseSensitive or caseInsensitive
2359+ */
2360+ bool isMember(const SBuf &, SBufCaseSensitive case_sensitive = caseSensitive);
2361+
2362+ /** check whether SBuf is prefix of any member in the list
2363+ * \param case_sensitive one of caseSensitive or caseInsensitive
2364+ */
2365+ bool isPrefix(const SBuf &, SBufCaseSensitive case_sensitive = caseSensitive);
2366+};
2367+
2368+#endif /* SQUID_SBUFLIST_H */
2369
2370=== added file 'src/SBufStream.h'
2371--- src/SBufStream.h 1970-01-01 00:00:00 +0000
2372+++ src/SBufStream.h 2013-07-04 15:56:30 +0000
2373@@ -0,0 +1,141 @@
2374+/*
2375+ * SQUID Web Proxy Cache http://www.squid-cache.org/
2376+ * ----------------------------------------------------------
2377+ *
2378+ * Squid is the result of efforts by numerous individuals from
2379+ * the Internet community; see the CONTRIBUTORS file for full
2380+ * details. Many organizations have provided support for Squid's
2381+ * development; see the SPONSORS file for full details. Squid is
2382+ * Copyrighted (C) 2001 by the Regents of the University of
2383+ * California; see the COPYRIGHT file for full details. Squid
2384+ * incorporates software developed and/or copyrighted by other
2385+ * sources; see the CREDITS file for full details.
2386+ *
2387+ * This program is free software; you can redistribute it and/or modify
2388+ * it under the terms of the GNU General Public License as published by
2389+ * the Free Software Foundation; either version 2 of the License, or
2390+ * (at your option) any later version.
2391+ *
2392+ * This program is distributed in the hope that it will be useful,
2393+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2394+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2395+ * GNU General Public License for more details.
2396+ *
2397+ * You should have received a copy of the GNU General Public License
2398+ * along with this program; if not, write to the Free Software
2399+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
2400+ *
2401+ */
2402+
2403+#ifndef SQUID_SBUFSTREAM_H
2404+#define SQUID_SBUFSTREAM_H
2405+
2406+#include "SBuf.h"
2407+
2408+#if HAVE_OSTREAM
2409+#include <ostream>
2410+#endif
2411+
2412+/**
2413+ * streambuf class for a SBuf-backed stream interface.
2414+ *
2415+ */
2416+class SBufStreamBuf : public std::streambuf
2417+{
2418+public:
2419+ /// initialize streambuf; use supplied SBuf as backing store
2420+ SBufStreamBuf(SBuf aBuf) : theBuf(aBuf) {}
2421+
2422+ /// get a copy of the stream's contents
2423+ SBuf getBuf() {
2424+ return theBuf;
2425+ }
2426+
2427+ /// clear the stream's store
2428+ void clearBuf() {
2429+ theBuf.clear();
2430+ }
2431+
2432+protected:
2433+ virtual int_type overflow(int_type aChar = traits_type::eof()) {
2434+ std::streamsize pending(pptr() - pbase());
2435+
2436+ if (pending && sync())
2437+ return traits_type::eof();
2438+
2439+ if (aChar != traits_type::eof()) {
2440+ char chars[1] = {static_cast<char>(aChar)};
2441+
2442+ if (aChar != traits_type::eof())
2443+ theBuf.append(chars, 0, 1);
2444+ }
2445+
2446+ pbump(-pending); // Reset pptr().
2447+ return aChar;
2448+ }
2449+
2450+ /* push the streambuf to the backing SBuf */
2451+ virtual int sync() {
2452+ std::streamsize pending(pptr() - pbase());
2453+
2454+ if (pending)
2455+ theBuf.append(pbase(), 0, pending);
2456+
2457+ return 0;
2458+ }
2459+
2460+ /* write multiple characters to the store entry
2461+ * - this is an optimisation method.
2462+ */
2463+ virtual std::streamsize xsputn(const char * chars, std::streamsize number) {
2464+ if (number)
2465+ theBuf.append(chars, 0, number);
2466+
2467+ return number;
2468+ }
2469+
2470+private:
2471+ SBuf theBuf;
2472+ SBufStreamBuf(); // no default constructor
2473+};
2474+
2475+/** Stream interface to write to a SBuf.
2476+ *
2477+ * Data is appended using standard operator << semantics, and extracted
2478+ * using the buf() method, in analogy with std::strstream .
2479+ */
2480+class SBufStream : public std::ostream
2481+{
2482+public:
2483+ /** Create a SBufStream preinitialized with the argument's SBuf.
2484+ *
2485+ * The supplied SBuf is not aliased: in order to retrieve the altered contents
2486+ * they must be fetched using the buf() class method.
2487+ */
2488+ SBufStream(SBuf aBuf): std::ostream(0), theBuffer(aBuf) {
2489+ rdbuf(&theBuffer); // set the buffer to now-initialized theBuffer
2490+ clear(); //clear badbit set by calling init(0)
2491+ }
2492+
2493+ /// Create an empty SBufStream
2494+ SBufStream(): std::ostream(0), theBuffer(SBuf()) {
2495+ rdbuf(&theBuffer); // set the buffer to now-initialized theBuffer
2496+ clear(); //clear badbit set by calling init(0)
2497+ }
2498+
2499+ /// Retrieve a copy of the current stream status
2500+ SBuf buf() {
2501+ return theBuffer.getBuf();
2502+ }
2503+
2504+ /// Clear the stream's backing store
2505+ SBufStream& clearBuf() {
2506+ theBuffer.clearBuf();
2507+ return *this;
2508+ }
2509+
2510+private:
2511+ SBufStreamBuf theBuffer;
2512+};
2513+
2514+#endif /* SQUID_SBUFSTREAM_H */
2515
2516=== added file 'src/SBufTokenizer.cc'
2517--- src/SBufTokenizer.cc 1970-01-01 00:00:00 +0000
2518+++ src/SBufTokenizer.cc 2013-07-04 15:56:30 +0000
2519@@ -0,0 +1,68 @@
2520+/*
2521+ * SBufTokenizer.cc (C) 2008 Francesco Chemollli <kinkie@squid-cache.org>
2522+ *
2523+ * SQUID Web Proxy Cache http://www.squid-cache.org/
2524+ * ----------------------------------------------------------
2525+ *
2526+ * Squid is the result of efforts by numerous individuals from
2527+ * the Internet community; see the CONTRIBUTORS file for full
2528+ * details. Many organizations have provided support for Squid's
2529+ * development; see the SPONSORS file for full details. Squid is
2530+ * Copyrighted (C) 2001 by the Regents of the University of
2531+ * California; see the COPYRIGHT file for full details. Squid
2532+ * incorporates software developed and/or copyrighted by other
2533+ * sources; see the CREDITS file for full details.
2534+ *
2535+ * This program is free software; you can redistribute it and/or modify
2536+ * it under the terms of the GNU General Public License as published by
2537+ * the Free Software Foundation; either version 2 of the License, or
2538+ * (at your option) any later version.
2539+ *
2540+ * This program is distributed in the hope that it will be useful,
2541+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2542+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2543+ * GNU General Public License for more details.
2544+ *
2545+ * You should have received a copy of the GNU General Public License
2546+ * along with this program; if not, write to the Free Software
2547+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
2548+ */
2549+
2550+#include "squid.h"
2551+#include "Debug.h"
2552+#include "SBufTokenizer.h"
2553+
2554+void SBufTokenizer::reset(const SBuf &toparse, const SBuf &delim)
2555+{
2556+ debugs(24, 4, "SBufTokenizer::reset()");
2557+ _toParse = toparse;
2558+ _delim = delim;
2559+ _lastToken.clear();
2560+ _lastDelim = 0;
2561+ next();
2562+}
2563+
2564+SBufTokenizer& SBufTokenizer::next()
2565+{
2566+ debugs(24, 7, "SBufTokenizer::next()");
2567+ SBuf::size_type tok;
2568+ tok = _toParse.find_first_of(_delim);
2569+ if (tok == SBuf::npos) {
2570+ debugs(24, 8, "SBufTokenizer::token(): separator not found");
2571+ _lastToken = _toParse;
2572+ _toParse.clear();
2573+ _lastDelim = '\0';
2574+ } else {
2575+ _lastDelim = _toParse[tok];
2576+ _lastToken = _toParse.consume(tok);
2577+ _toParse.consume(1); //the separator
2578+ }
2579+ return *this;
2580+}
2581+
2582+bool SBufTokenizer::atEnd() const
2583+{
2584+ debugs(24, 8, "result: " << (_toParse.length() == 0));
2585+ return (_toParse.length() == 0 && _lastToken.length() == 0);
2586+}
2587+
2588
2589=== added file 'src/SBufTokenizer.h'
2590--- src/SBufTokenizer.h 1970-01-01 00:00:00 +0000
2591+++ src/SBufTokenizer.h 2013-07-04 15:56:30 +0000
2592@@ -0,0 +1,149 @@
2593+/*
2594+ * SBuTokenizer.h (C) 2008 Francesco Chemollli <kinkie@squid-cache.org>
2595+ *
2596+ * SQUID Web Proxy Cache http://www.squid-cache.org/
2597+ * ----------------------------------------------------------
2598+ *
2599+ * Squid is the result of efforts by numerous individuals from
2600+ * the Internet community; see the CONTRIBUTORS file for full
2601+ * details. Many organizations have provided support for Squid's
2602+ * development; see the SPONSORS file for full details. Squid is
2603+ * Copyrighted (C) 2001 by the Regents of the University of
2604+ * California; see the COPYRIGHT file for full details. Squid
2605+ * incorporates software developed and/or copyrighted by other
2606+ * sources; see the CREDITS file for full details.
2607+ *
2608+ * This program is free software; you can redistribute it and/or modify
2609+ * it under the terms of the GNU General Public License as published by
2610+ * the Free Software Foundation; either version 2 of the License, or
2611+ * (at your option) any later version.
2612+ *
2613+ * This program is distributed in the hope that it will be useful,
2614+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2615+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2616+ * GNU General Public License for more details.
2617+ *
2618+ * You should have received a copy of the GNU General Public License
2619+ * along with this program; if not, write to the Free Software
2620+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
2621+ */
2622+
2623+#ifndef SQUID_SBUFTOKENIZER_H
2624+#define SQUID_SBUFTOKENIZER_H
2625+
2626+#include "SBuf.h"
2627+
2628+/**
2629+ * A tokenizer for SBuf
2630+ * example:
2631+ * \code
2632+ * SBuf toparse, sep;
2633+ * toparse = ...; sep = ...;
2634+ * for (SBufTokenizer st(toparse,sep);!st.atEnd();st.next()) {
2635+ * SBuf s = st.token();
2636+ * //...
2637+ * }
2638+ * \endcode
2639+ */
2640+class SBufTokenizer
2641+{
2642+public:
2643+ /** Constructor
2644+ *
2645+ * create a new SBufTokenizer to check over the contents of toparse,
2646+ * using any of the characters of delim as a token delimiter
2647+ * \param toparse the SBuf to be tokenized
2648+ * \param delim the token separator. It's a SBuf which is interpreted
2649+ * as a bag of chars, whose each is a possible token delimiter.
2650+ */
2651+ SBufTokenizer(const SBuf &toparse, const SBuf &delim)
2652+ {
2653+ reset(toparse,delim);
2654+ }
2655+
2656+ /** reset the Tokenizer
2657+ *
2658+ * reset the SBufTokenizer with a new SBuf to be parsed and a new
2659+ * delimiter set.
2660+ * \param toparse the SBuf to be tokenized
2661+ * \param delim the token separator. It's a SBuf which is interpreted
2662+ */
2663+ void reset(const SBuf &toparse, const SBuf &delim);
2664+
2665+ /** set a new delimiter set
2666+ *
2667+ * \param newdelim the token separator.
2668+ */
2669+ void setDelimiter(const SBuf &newdelim)
2670+ {
2671+ _delim = newdelim;
2672+ }
2673+
2674+ /** retrieve the current delimiter set
2675+ */
2676+ SBuf getDelimiter() const
2677+ {
2678+ return _delim;
2679+ }
2680+
2681+ /** Extract the next Token
2682+ *
2683+ * strtok()-equivalent.
2684+ * Will extract a token from the beginning of the SBuf, containing
2685+ * all chars up to the first occurrence of any of the chars in
2686+ * <i>delim</i> or end-of-SBuf if no delimiter can be found.
2687+ * The tokenized SBuf is modified, by removing its head
2688+ * the to-be-returned token AND the delimiter.
2689+ */
2690+ SBufTokenizer& next();
2691+
2692+ /** get last delimiter found
2693+ *
2694+ ** returns the delimiter which terminated the last-matched token
2695+ * If no token() has not been extracted or we are at the end of the
2696+ * SBuf to be tokenized, the result is undefined
2697+ */
2698+ char separator() const
2699+ {
2700+ return _lastDelim;
2701+ }
2702+
2703+ /** Move to the next token, specify new delimiter
2704+ *
2705+ * Move to the next token, and a new delimiter to parse it
2706+ */
2707+ SBufTokenizer &next(const SBuf &newdelim)
2708+ {
2709+ setDelimiter(newdelim);
2710+ return next();
2711+ }
2712+
2713+ /** Extract a token
2714+ *
2715+ * Extract a token from the SBuf. May be called repeatedly, in that case
2716+ * will return each time a fresh copy of the same token.
2717+ */
2718+ SBuf token() const
2719+ {
2720+ return _lastToken;
2721+ }
2722+
2723+ /** check whether we are done
2724+ *
2725+ * \retval true if we are at the SBuf to be parsed.
2726+ */
2727+ bool atEnd() const;
2728+
2729+private:
2730+ SBuf _toParse; /// the still-unparsed part of the buffer to parse
2731+ SBuf _lastToken;/// the last returned token
2732+ char _lastDelim;/// the delimiter last matched
2733+ SBuf _delim; /// a SBuf containing the delimiter characters
2734+
2735+ SBuf::size_type pbrk() const
2736+ {
2737+ return _toParse.find_first_of(_delim);
2738+ }
2739+};
2740+
2741+#endif
2742
2743=== added file 'src/SBufUtil.cc'
2744--- src/SBufUtil.cc 1970-01-01 00:00:00 +0000
2745+++ src/SBufUtil.cc 2013-07-04 15:56:30 +0000
2746@@ -0,0 +1,64 @@
2747+/*
2748+ * SBufUtil.cc (C) 2009 Francesco Chemolli <kinkie@squid-cache.org>
2749+ *
2750+ * SQUID Web Proxy Cache http://www.squid-cache.org/
2751+ * ----------------------------------------------------------
2752+ *
2753+ * Squid is the result of efforts by numerous individuals from
2754+ * the Internet community; see the CONTRIBUTORS file for full
2755+ * details. Many organizations have provided support for Squid's
2756+ * development; see the SPONSORS file for full details. Squid is
2757+ * Copyrighted (C) 2001 by the Regents of the University of
2758+ * California; see the COPYRIGHT file for full details. Squid
2759+ * incorporates software developed and/or copyrighted by other
2760+ * sources; see the CREDITS file for full details.
2761+ *
2762+ * This program is free software; you can redistribute it and/or modify
2763+ * it under the terms of the GNU General Public License as published by
2764+ * the Free Software Foundation; either version 2 of the License, or
2765+ * (at your option) any later version.
2766+ *
2767+ * This program is distributed in the hope that it will be useful,
2768+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2769+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2770+ * GNU General Public License for more details.
2771+ *
2772+ * You should have received a copy of the GNU General Public License
2773+ * along with this program; if not, write to the Free Software
2774+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
2775+ */
2776+
2777+#include "squid.h"
2778+#include "SBufUtil.h"
2779+
2780+SBuf
2781+SBufListJoin(SBufList &list, const SBuf &separator)
2782+{
2783+ SBufList::iterator i;
2784+ SBuf::size_type sz = 0;
2785+ //first thing: calculate the length to reserveSpace
2786+ for (i = list.begin(); i!= list.end(); ++i)
2787+ sz += (*i).length()+separator.length();
2788+ SBuf rv;
2789+ rv.reserveSpace(sz);
2790+ i = list.begin();
2791+ if (i != list.end())
2792+ rv.append(*i);
2793+ ++i;
2794+ if (i != list.end()) {
2795+ for (; i!= list.end(); i++) {
2796+ rv.append(separator);
2797+ rv.append(*i);
2798+ }
2799+ }
2800+ return rv;
2801+}
2802+
2803+SBuf
2804+BaseName(const SBuf &s, char separator)
2805+{
2806+ SBuf::size_type pos = s.rfind(separator);
2807+ if (pos == SBuf::npos)
2808+ return s;
2809+ return s.substr(pos+1);
2810+}
2811
2812=== added file 'src/SBufUtil.h'
2813--- src/SBufUtil.h 1970-01-01 00:00:00 +0000
2814+++ src/SBufUtil.h 2013-07-04 15:56:30 +0000
2815@@ -0,0 +1,51 @@
2816+/*
2817+ * SBufUtil.h (C) 2009 Francesco Chemolli <kinkie@squid-cache.org>
2818+ *
2819+ * SQUID Web Proxy Cache http://www.squid-cache.org/
2820+ * ----------------------------------------------------------
2821+ *
2822+ * Squid is the result of efforts by numerous individuals from
2823+ * the Internet community; see the CONTRIBUTORS file for full
2824+ * details. Many organizations have provided support for Squid's
2825+ * development; see the SPONSORS file for full details. Squid is
2826+ * Copyrighted (C) 2001 by the Regents of the University of
2827+ * California; see the COPYRIGHT file for full details. Squid
2828+ * incorporates software developed and/or copyrighted by other
2829+ * sources; see the CREDITS file for full details.
2830+ *
2831+ * This program is free software; you can redistribute it and/or modify
2832+ * it under the terms of the GNU General Public License as published by
2833+ * the Free Software Foundation; either version 2 of the License, or
2834+ * (at your option) any later version.
2835+ *
2836+ * This program is distributed in the hope that it will be useful,
2837+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2838+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2839+ * GNU General Public License for more details.
2840+ *
2841+ * You should have received a copy of the GNU General Public License
2842+ * along with this program; if not, write to the Free Software
2843+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
2844+ */
2845+
2846+#ifndef SQUID_SBUFUTIL_H
2847+#define SQUID_SBUFUTIL_H
2848+
2849+#include "SBuf.h"
2850+#include "SBufList.h"
2851+#include "SBufTokenizer.h"
2852+
2853+/** join a SBufList into a SBuf using the supplied separator.
2854+ */
2855+SBuf SBufListJoin(SBufList &list, const SBuf &separator);
2856+
2857+/** Obtain the basename of a file.
2858+ *
2859+ * Returns the part of a SBuf after the last occurrence of the specified delimiter.
2860+ * If the delimiter is not found, return the whole SBuf
2861+ * \param s the SBuf to be analyzed
2862+ * \param separator the separating character (defaults to '/')
2863+ */
2864+SBuf BaseName(const SBuf &s, char separator = '/');
2865+
2866+#endif /* SQUID_SBUFUTIL_H */
2867
2868=== modified file 'src/SquidString.h'
2869--- src/SquidString.h 2012-09-22 10:56:48 +0000
2870+++ src/SquidString.h 2013-07-04 15:56:30 +0000
2871@@ -43,40 +43,6 @@
2872 #define SQUIDSTRINGPRINT(s) (s).psize(),(s).rawBuf()
2873 #endif /* SQUIDSTRINGPH */
2874
2875-#define DEBUGSTRINGS 0
2876-#if DEBUGSTRINGS
2877-#include "splay.h"
2878-
2879-class String;
2880-
2881-class StringRegistry
2882-{
2883-
2884-public:
2885- static StringRegistry &Instance();
2886-
2887- void add(String const *);
2888-
2889- StringRegistry();
2890-
2891- void remove(String const *);
2892-
2893-private:
2894- static OBJH Stat;
2895-
2896- static StringRegistry Instance_;
2897-
2898- static SplayNode<String const *>::SPLAYWALKEE Stater;
2899-
2900- Splay<String const *> entries;
2901-
2902- bool registered;
2903-
2904-};
2905-
2906-class StoreEntry;
2907-#endif
2908-
2909 class String
2910 {
2911
2912@@ -150,10 +116,6 @@
2913
2914 _SQUID_INLINE_ void cut(size_type newLength);
2915
2916-#if DEBUGSTRINGS
2917- void stat(StoreEntry *) const;
2918-#endif
2919-
2920 private:
2921 void allocAndFill(const char *str, int len);
2922 void allocBuffer(size_type sz);
2923
2924=== modified file 'src/StrList.h'
2925--- src/StrList.h 2012-09-21 14:57:30 +0000
2926+++ src/StrList.h 2013-07-04 15:56:30 +0000
2927@@ -1,7 +1,4 @@
2928 /*
2929- * DEBUG: section 66 HTTP Header Tools
2930- * AUTHOR: Alex Rousskov
2931- *
2932 * SQUID Web Proxy Cache http://www.squid-cache.org/
2933 * ----------------------------------------------------------
2934 *
2935@@ -28,16 +25,77 @@
2936 * along with this program; if not, write to the Free Software
2937 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
2938 *
2939+ * Copyright (c) 2010 Francesco Chemolli <kinkie@squid-cache.org>
2940 */
2941
2942-#ifndef SQUID_STRLIST_H_
2943-#define SQUID_STRLIST_H_
2944+#ifndef STRLIST_H_
2945+#define STRLIST_H_
2946
2947-class String;
2948+#include "SBufList.h"
2949+#include "SBufUtil.h"
2950+#include "SquidString.h"
2951+#include "protos.h"
2952
2953 void strListAdd(String * str, const char *item, char del);
2954 int strListIsMember(const String * str, const char *item, char del);
2955 int strListIsSubstr(const String * list, const char *s, char del);
2956 int strListGetItem(const String * str, char del, const char **item, int *ilen, const char **pos);
2957
2958-#endif /* SQUID_STRLIST_H_ */
2959+#if 0
2960+/* incomplete code, do not use!
2961+ * It is meant to eventually turn the strList* functions into proper object
2962+ * manipulators.
2963+ * TODO: finish and use it.
2964+ */
2965+class StrList
2966+{
2967+public:
2968+ StrList() { }
2969+ explicit StrList(const SBufList &s) {
2970+ const SBuf sep(", ");
2971+ SBuf b=SBufListJoin(s,sep);
2972+ data_=b.toString();
2973+ }
2974+ explicit StrList(const char *s) {
2975+ data_=s;
2976+ }
2977+ explicit StrList (const SBuf &s) {
2978+ data_=s.toString();
2979+ }
2980+ ~StrList() { data_.clean(); };
2981+ void StrListAdd(const char *item, char del) {
2982+ strListAdd(&data_,item,del);
2983+ }
2984+ int StrListIsMember(const char *item, char del=',') {
2985+ return strListIsMember(&data_,item,del);
2986+ }
2987+ int StrListIsSubstr(const char *s, char del) {
2988+ return strListIsSubstr(&data_, s, del);
2989+ }
2990+ int StrListGetItem(char del, const char **item, int *ilen, const char **pos) {
2991+ return strListGetItem(&data_, del, item, ilen, pos);
2992+ }
2993+ String StrListGetString() {
2994+ return data_;
2995+ }
2996+ void clear() {
2997+ data_.clean();
2998+ }
2999+ void append(char const *buf, int len) {
3000+ data_.append(buf,len);
3001+ }
3002+ void append(char const *buf) {
3003+ data_.append(buf);
3004+ }
3005+ String::size_type size() const {
3006+ return data_.size();
3007+ }
3008+
3009+private:
3010+ String data_;
3011+ SBufList ndata;
3012+};
3013+
3014+#endif
3015+
3016+#endif /* STRLIST_H_ */
3017
3018=== modified file 'src/icmp/Makefile.am'
3019--- src/icmp/Makefile.am 2010-11-01 05:44:28 +0000
3020+++ src/icmp/Makefile.am 2013-07-04 15:56:30 +0000
3021@@ -22,6 +22,25 @@
3022
3023 noinst_LTLIBRARIES = libicmp-core.la libicmp.la
3024
3025+SBUF_SOURCE= \
3026+ $(top_srcdir)/src/SBuf.h \
3027+ $(top_srcdir)/src/SBuf.cc \
3028+ $(top_srcdir)/src/MemBlob.h \
3029+ $(top_srcdir)/src/MemBlob.cc \
3030+ $(top_srcdir)/src/OutOfBoundsException.h \
3031+ $(top_srcdir)/src/SBufExceptions.h \
3032+ $(top_srcdir)/src/SBufExceptions.cc \
3033+ $(top_srcdir)/src/SBufTokenizer.h \
3034+ $(top_srcdir)/src/SBufTokenizer.cc \
3035+ $(top_srcdir)/src/SBufList.h \
3036+ $(top_srcdir)/src/SBufList.cc \
3037+ $(top_srcdir)/src/SBufUtil.h \
3038+ $(top_srcdir)/src/SBufUtil.cc \
3039+ $(top_srcdir)/src/String.cc \
3040+ $(top_srcdir)/src/SquidString.h \
3041+ $(top_srcdir)/src/base/TextException.h \
3042+ $(top_srcdir)/src/base/TextException.cc
3043+
3044 # ICMP API definition ...
3045 libicmp_core_la_SOURCES = \
3046 Icmp.h \
3047
3048=== added file 'src/tests/SBufFindTest.cc'
3049--- src/tests/SBufFindTest.cc 1970-01-01 00:00:00 +0000
3050+++ src/tests/SBufFindTest.cc 2013-07-04 15:56:30 +0000
3051@@ -0,0 +1,418 @@
3052+#include "squid.h"
3053+#include "SBufFindTest.h"
3054+#include <cppunit/extensions/HelperMacros.h>
3055+#include <cppunit/Message.h>
3056+#include <limits>
3057+
3058+
3059+/* TODO: The whole SBufFindTest class is currently implemented as a single
3060+ CppUnit test case (because we do not want to register and report every one
3061+ of the thousands of generated test cases). Is there a better way to
3062+ integrate with CppUnit?
3063+ */
3064+
3065+
3066+SBufFindTest::SBufFindTest():
3067+ caseLimit(std::numeric_limits<int>::max()),
3068+ errorLimit(std::numeric_limits<int>::max()),
3069+ randomSeed(1),
3070+ hushSimilar(true),
3071+ maxHayLength(40),
3072+ thePos(0),
3073+ thePlacement(placeEof),
3074+ theStringPos(0),
3075+ theBareNeedlePos(0),
3076+ caseCount(0),
3077+ errorCount(0),
3078+ reportCount(0)
3079+{
3080+}
3081+
3082+void
3083+SBufFindTest::run()
3084+{
3085+ srandom(randomSeed);
3086+
3087+ for (SBuf::size_type hayLen = 0; hayLen <= maxHayLength; nextLen(hayLen, maxHayLength)) {
3088+ const SBuf cleanHay = RandomSBuf(hayLen);
3089+
3090+ const SBuf::size_type maxNeedleLen = hayLen + 10;
3091+ for (SBuf::size_type needleLen = 0; needleLen <= maxNeedleLen; nextLen(needleLen, maxNeedleLen)) {
3092+ theSBufNeedle = RandomSBuf(needleLen);
3093+
3094+ for (int i = 0; i < placeEof; i++) {
3095+ thePlacement = Placement(i);
3096+ placeNeedle(cleanHay);
3097+
3098+ const SBuf::size_type maxArg =
3099+ max(theSBufHay.length(), theSBufNeedle.length()) + 10;
3100+ for (thePos = 0; thePos <= maxArg; nextLen(thePos, maxArg))
3101+ testAllMethods();
3102+
3103+ // also test the special npos value
3104+ thePos = SBuf::npos;
3105+ testAllMethods();
3106+ }
3107+ }
3108+ }
3109+
3110+ if (errorCount > 0) {
3111+ std::cerr << "Generated SBuf test cases: " << caseCount << std::endl;
3112+ std::cerr << "\tfailed cases: " << errorCount << std::endl;
3113+ std::cerr << "\treported cases: " << reportCount << std::endl;
3114+ std::cerr << "Asserting because some cases failed..." << std::endl;
3115+ CPPUNIT_ASSERT(!SBufFindTest::errorCount);
3116+ }
3117+}
3118+
3119+/// tests SBuf::find(string needle)
3120+void
3121+SBufFindTest::testFindDefs() {
3122+ theFindString = theBareNeedlePos = theStringHay.find(theStringNeedle);
3123+ theFindSBuf = theSBufHay.find(theSBufNeedle);
3124+ checkResults("find");
3125+}
3126+
3127+/// tests SBuf::rfind(string needle)
3128+void
3129+SBufFindTest::testRFindDefs() {
3130+ theFindString = theBareNeedlePos = theStringHay.rfind(theStringNeedle);
3131+ theFindSBuf = theSBufHay.rfind(theSBufNeedle);
3132+ checkResults("rfind");
3133+}
3134+
3135+/// tests SBuf::find(string needle, pos)
3136+void
3137+SBufFindTest::testFind() {
3138+ theFindString = theStringHay.find(theStringNeedle, thePos);
3139+ theBareNeedlePos = theStringHay.find(theStringNeedle);
3140+ theFindSBuf = theSBufHay.find(theSBufNeedle, thePos);
3141+ checkResults("find");
3142+}
3143+
3144+/// tests SBuf::rfind(string needle, pos)
3145+void
3146+SBufFindTest::testRFind() {
3147+ theFindString = theStringHay.rfind(theStringNeedle, thePos);
3148+ theBareNeedlePos = theStringHay.rfind(theStringNeedle);
3149+ theFindSBuf = theSBufHay.rfind(theSBufNeedle, thePos);
3150+ checkResults("rfind");
3151+}
3152+
3153+/// tests SBuf::find(char needle)
3154+void
3155+SBufFindTest::testFindCharDefs() {
3156+ const char c = theStringNeedle[0];
3157+ theFindString = theBareNeedlePos = theStringHay.find(c);
3158+ theFindSBuf = theSBufHay.find(c);
3159+ checkResults("find");
3160+}
3161+
3162+/// tests SBuf::find(char needle, pos)
3163+void
3164+SBufFindTest::testFindChar() {
3165+ const char c = theStringNeedle[0];
3166+ theFindString = theStringHay.find(c, thePos);
3167+ theBareNeedlePos = theStringHay.find(c);
3168+ theFindSBuf = theSBufHay.find(c, thePos);
3169+ checkResults("find");
3170+}
3171+
3172+/// tests SBuf::rfind(char needle)
3173+void
3174+SBufFindTest::testRFindCharDefs() {
3175+ const char c = theStringNeedle[0];
3176+ theFindString = theBareNeedlePos = theStringHay.rfind(c);
3177+ theFindSBuf = theSBufHay.rfind(c);
3178+ checkResults("rfind");
3179+}
3180+
3181+/// tests SBuf::rfind(char needle, pos)
3182+void
3183+SBufFindTest::testRFindChar() {
3184+ const char c = theStringNeedle[0];
3185+ theFindString = theStringHay.rfind(c, thePos);
3186+ theBareNeedlePos = theStringHay.rfind(c);
3187+ theFindSBuf = theSBufHay.rfind(c, thePos);
3188+ checkResults("rfind");
3189+}
3190+
3191+/// whether the last SBuf and std::string find() results are the same
3192+bool
3193+SBufFindTest::resultsMatch() const {
3194+ // this method is needed because SBuf and std::string use different
3195+ // size_types (and npos values); comparing the result values directly
3196+ // would lead to bugs
3197+
3198+ if (theFindString == std::string::npos && theFindSBuf == SBuf::npos)
3199+ return true; // both npos
3200+
3201+ if (theFindSBuf < 0) // should not happen, treat as error
3202+ return false;
3203+
3204+ // now safe to cast a non-negative SBuf result
3205+ return theFindString == static_cast<std::string::size_type>(theFindSBuf);
3206+}
3207+
3208+/// called at the end of test case to update state, detect and report failures
3209+void
3210+SBufFindTest::checkResults(const char *method) {
3211+ ++caseCount;
3212+ if (!resultsMatch())
3213+ handleFailure(method);
3214+}
3215+
3216+/// helper function to convert "printable" Type to std::string
3217+template<typename Type>
3218+inline std::string
3219+AnyToString(const Type &value)
3220+{
3221+ std::stringstream sbuf;
3222+ sbuf << value;
3223+ return sbuf.str();
3224+}
3225+
3226+/// helper function to convert SBuf position to a human-friendly string
3227+inline std::string
3228+PosToString(const SBuf::size_type pos)
3229+{
3230+ return pos == SBuf::npos ? std::string("npos") : AnyToString(pos);
3231+}
3232+
3233+/// helper function to convert std::string position to a human-friendly string
3234+inline std::string
3235+PosToString(const std::string::size_type pos)
3236+{
3237+ return pos == std::string::npos ? std::string("npos") : AnyToString(pos);
3238+}
3239+
3240+/// tests each supported SBuf::*find() method using generated hay, needle, pos
3241+void
3242+SBufFindTest::testAllMethods() {
3243+ theStringHay = std::string(theSBufHay.rawContent(), theSBufHay.length());
3244+ theStringNeedle = std::string(theSBufNeedle.rawContent(), theSBufNeedle.length());
3245+ theBareNeedlePos = std::string::npos;
3246+ const std::string reportPos = PosToString(thePos);
3247+
3248+ // always test string search
3249+ {
3250+ theReportQuote = '"';
3251+ theReportNeedle = theStringNeedle;
3252+
3253+ theReportPos = "";
3254+ testFindDefs();
3255+ testRFindDefs();
3256+
3257+ theReportPos = reportPos;
3258+ testFind();
3259+ testRFind();
3260+ }
3261+
3262+ // if possible, test char search
3263+ if (!theStringNeedle.empty()) {
3264+ theReportQuote = '\'';
3265+ theReportNeedle = theStringNeedle[0];
3266+
3267+ theReportPos = "";
3268+ testFindCharDefs();
3269+ testRFindCharDefs();
3270+
3271+ theReportPos = reportPos;
3272+ testFindChar();
3273+ testRFindChar();
3274+ }
3275+}
3276+
3277+/// helper function to format a length-based key (part of case category string)
3278+inline std::string
3279+lengthKey(const std::string &str)
3280+{
3281+ if (str.length() == 0)
3282+ return "0";
3283+ if (str.length() == 1)
3284+ return "1";
3285+ return "N";
3286+}
3287+
3288+/// formats position key (part of the case category string)
3289+std::string
3290+SBufFindTest::posKey() const
3291+{
3292+ // the search position does not matter if needle is not in hay
3293+ if (theBareNeedlePos == std::string::npos)
3294+ return std::string();
3295+
3296+ if (thePos == SBuf::npos)
3297+ return ",npos";
3298+
3299+ if (thePos < 0)
3300+ return ",posN"; // negative
3301+
3302+ // we know Pos is not negative or special; avoid signed/unsigned warnings
3303+ const std::string::size_type pos =
3304+ static_cast<std::string::size_type>(thePos);
3305+
3306+ if (pos < theBareNeedlePos)
3307+ return ",posL"; // to the Left of the needle
3308+ if (pos == theBareNeedlePos)
3309+ return ",posB"; // Beginning of the needle
3310+ if (pos < theBareNeedlePos + theStringNeedle.length())
3311+ return ",posM"; // in the Middle of the needle
3312+ if (pos == theBareNeedlePos + theStringNeedle.length())
3313+ return ",posE"; // at the End of the needle
3314+ if (pos < theStringHay.length())
3315+ return ",posR"; // to the Right of the needle
3316+ return ",posP"; // past the hay
3317+}
3318+
3319+/// formats placement key (part of the case category string)
3320+std::string
3321+SBufFindTest::placementKey() const
3322+{
3323+ // Ignore thePlacement because theBareNeedlePos covers it better: we may
3324+ // try to place the needle somewhere, but hay limits the actual placement.
3325+
3326+ // the placent does not matter if needle is not in hay
3327+ if (theBareNeedlePos == std::string::npos)
3328+ return std::string();
3329+
3330+ if (theBareNeedlePos == 0)
3331+ return "@B"; // at the beggining of the hay string
3332+ if (theBareNeedlePos == theStringHay.length()-theStringNeedle.length())
3333+ return "@E"; // at the end of the hay string
3334+ return "@M"; // in the "middle" of the hay string
3335+}
3336+
3337+/// called when a test case fails; counts and possibly reports the failure
3338+void
3339+SBufFindTest::handleFailure(const char *method) {
3340+ // line break after "........." printed for previous tests
3341+ if (!errorCount)
3342+ std::cerr << std::endl;
3343+
3344+ ++errorCount;
3345+
3346+ if (errorCount > errorLimit) {
3347+ std::cerr << "Will stop generating SBuf test cases because the " <<
3348+ "number of failed ones is over the limit: " << errorCount <<
3349+ " (after " << caseCount << " test cases)" << std::endl;
3350+ CPPUNIT_ASSERT(errorCount <= errorLimit);
3351+ /* NOTREACHED */
3352+ }
3353+
3354+ // format test case category; category allows us to hush failure reports
3355+ // for already seen categories with failed cases (to reduce output noise)
3356+ std::string category = "hay" + lengthKey(theStringHay) +
3357+ "." + method + '(';
3358+ if (theReportQuote == '"')
3359+ category += "needle" + lengthKey(theStringNeedle);
3360+ else
3361+ category += "char";
3362+ category += placementKey();
3363+ category += posKey();
3364+ category += ')';
3365+
3366+ if (hushSimilar) {
3367+ if (failedCats.find(category) != failedCats.end())
3368+ return; // do not report another similar test case failure
3369+ failedCats.insert(category);
3370+ }
3371+
3372+ std::string reportPos = theReportPos;
3373+ if (!reportPos.empty())
3374+ reportPos = ", " + reportPos;
3375+
3376+ std::cerr << "case" << caseCount << ": " <<
3377+ "SBuf(\"" << theStringHay << "\")." << method <<
3378+ "(" << theReportQuote << theReportNeedle << theReportQuote <<
3379+ reportPos << ") returns " << PosToString(theFindSBuf) <<
3380+ " instead of " << PosToString(theFindString) <<
3381+ std::endl <<
3382+ " std::string(\"" << theStringHay << "\")." << method <<
3383+ "(" << theReportQuote << theReportNeedle << theReportQuote <<
3384+ reportPos << ") returns " << PosToString(theFindString) <<
3385+ std::endl <<
3386+ " category: " << category << std::endl;
3387+
3388+ ++reportCount;
3389+}
3390+
3391+/// generates a random string of the specified length
3392+SBuf
3393+SBufFindTest::RandomSBuf(const int length) {
3394+ static const char characters[] =
3395+ "0123456789"
3396+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
3397+ "abcdefghijklomnpqrstuvwxyz";
3398+ // sizeof() counts the terminating zero at the end of characters
3399+ // TODO: add \0 character (needs reporting adjustments to print it as \0)
3400+ static const size_t charCount = sizeof(characters)-1;
3401+
3402+ char buf[length];
3403+ for (int i = 0; i < length; ++i) {
3404+ const unsigned int pos = random() % charCount;
3405+ assert(pos < sizeof(characters));
3406+ assert(characters[pos] > 32);
3407+ buf[i] = characters[random() % charCount];
3408+ }
3409+
3410+ return SBuf(buf, 0, length);
3411+}
3412+
3413+/// increments len to quickly cover [0, max] range, slowing down in risky areas
3414+/// jumps to max+1 if caseLimit is reached
3415+void
3416+SBufFindTest::nextLen(int &len, const int max) {
3417+ assert(len <= max);
3418+
3419+ if (caseCount >= caseLimit)
3420+ len = max+1; // avoid future test cases
3421+ else if (len <= 10)
3422+ ++len; // move slowly at the beginning of the [0,max] range
3423+ else if (len >= max - 10)
3424+ ++len; // move slowly at the end of the [0,max] range
3425+ else {
3426+ // move fast in the middle of the [0,max] range
3427+ len += len/10 + 1;
3428+
3429+ // but do not overshoot the interesting area at the end of the range
3430+ if (len > max - 10)
3431+ len = max - 10;
3432+ }
3433+}
3434+
3435+/// Places the needle into the hay using cleanHay as a starting point.
3436+void
3437+SBufFindTest::placeNeedle(const SBuf &cleanHay) {
3438+ // For simplicity, we do not overwrite clean hay characters but use them as
3439+ // needle suffix and/or prefix. Should not matter since hay length varies?
3440+
3441+ // TODO: support two needles per hay (explicitly)
3442+ // TODO: better handle cases where clean hay already contains needle
3443+ switch (thePlacement)
3444+ {
3445+ case placeBeginning:
3446+ theSBufHay.assign(theSBufNeedle).append(cleanHay);
3447+ break;
3448+
3449+ case placeMiddle:
3450+ {
3451+ const SBuf firstHalf = cleanHay.substr(0, cleanHay.length()/2);
3452+ const SBuf secondHalf = cleanHay.substr(cleanHay.length()/2);
3453+ theSBufHay.assign(firstHalf).append(theSBufNeedle).append(secondHalf);
3454+ break;
3455+ }
3456+
3457+ case placeEnd:
3458+ theSBufHay.assign(cleanHay).append(theSBufNeedle);
3459+ break;
3460+
3461+ case placeNowhere:
3462+ theSBufHay.assign(cleanHay);
3463+ break;
3464+
3465+ case placeEof:
3466+ assert(false); // should not happen
3467+ break;
3468+ }
3469+}
3470
3471=== added file 'src/tests/SBufFindTest.h'
3472--- src/tests/SBufFindTest.h 1970-01-01 00:00:00 +0000
3473+++ src/tests/SBufFindTest.h 2013-07-04 15:56:30 +0000
3474@@ -0,0 +1,85 @@
3475+#ifndef SQUID_SRC_TEST_SBUFFINDTEST_H
3476+#define SQUID_SRC_TEST_SBUFFINDTEST_H
3477+
3478+#include "SBuf.h"
3479+
3480+#if HAVE_STRING
3481+#include <string>
3482+#endif
3483+#include <set>
3484+
3485+/// Generates and executes a [configurable] large number of SBuf::*find()
3486+/// test cases using random strings. Reports detected failures.
3487+class SBufFindTest
3488+{
3489+public:
3490+ SBufFindTest();
3491+
3492+ void run(); ///< generates and executes cases using configuration params
3493+
3494+ /* test configuration parameters; can be optionally set before run() */
3495+ int caseLimit; ///< approximate caseCount limit
3496+ int errorLimit; ///< errorCount limit
3497+ unsigned int randomSeed; ///< pseudo-random sequence choice
3498+ /// whether to report only one failed test case per "category"
3499+ bool hushSimilar;
3500+ /// approximate maximum generated hay string length
3501+ SBuf::size_type maxHayLength;
3502+
3503+ /// Supported algorithms for placing needle in the hay.
3504+ typedef enum { placeBeginning, placeMiddle, placeEnd, placeNowhere,
3505+ placeEof } Placement; // placeLast marker must terminate
3506+protected:
3507+
3508+ static SBuf RandomSBuf(const int length);
3509+ void nextLen(int &len, const int max);
3510+ void placeNeedle(const SBuf &cleanHay);
3511+
3512+ void testAllMethods();
3513+ void testFindDefs();
3514+ void testFind();
3515+ void testRFindDefs();
3516+ void testRFind();
3517+ void testFindCharDefs();
3518+ void testFindChar();
3519+ void testRFindCharDefs();
3520+ void testRFindChar();
3521+
3522+ std::string posKey() const;
3523+ std::string placementKey() const;
3524+
3525+ bool resultsMatch() const;
3526+ void checkResults(const char *method);
3527+ void handleFailure(const char *method);
3528+
3529+private:
3530+ /* test case parameters */
3531+ SBuf theSBufHay; ///< the string to be searched
3532+ SBuf theSBufNeedle; ///< the string to be found
3533+ SBuf::size_type thePos; ///< search position limit
3534+ Placement thePlacement; ///< where in the hay the needle is placed
3535+ std::string::size_type theStringPos; ///< thePos converted to std::string::size_type
3536+ std::string theStringHay; ///< theHay converted to std::string
3537+ std::string theStringNeedle; ///< theNeedle converted to std::string
3538+
3539+ /// needle pos w/o thePos restrictions; used for case categorization
3540+ std::string::size_type theBareNeedlePos;
3541+
3542+ /* test case results */
3543+ std::string::size_type theFindString;
3544+ SBuf::size_type theFindSBuf;
3545+ std::string theReportFunc;
3546+ std::string theReportNeedle;
3547+ std::string theReportPos;
3548+ char theReportQuote;
3549+
3550+ /* test progress indicators */
3551+ int caseCount; ///< cases executed so far
3552+ int errorCount; ///< total number of failed test cases so far
3553+ int reportCount; ///< total number of test cases reported so far
3554+ std::set<std::string> failedCats; ///< reported failed categories
3555+};
3556+
3557+typedef SBufFindTest::Placement Placement;
3558+
3559+#endif
3560
3561=== added file 'src/tests/testSBuf.cc'
3562--- src/tests/testSBuf.cc 1970-01-01 00:00:00 +0000
3563+++ src/tests/testSBuf.cc 2013-07-04 15:56:30 +0000
3564@@ -0,0 +1,603 @@
3565+#include "squid.h"
3566+#include "Mem.h"
3567+#include "SBuf.h"
3568+#include "SBufList.h"
3569+#include "SBufStream.h"
3570+#include "SBufTokenizer.h"
3571+#include "SBufUtil.h"
3572+#include "SquidString.h"
3573+#include "testSBuf.h"
3574+#include "SBufFindTest.h"
3575+
3576+#include <iostream>
3577+#include <stdexcept>
3578+
3579+CPPUNIT_TEST_SUITE_REGISTRATION( testSBuf );
3580+
3581+/* let this test link sanely */
3582+#include "event.h"
3583+#include "MemObject.h"
3584+void
3585+eventAdd(const char *name, EVH * func, void *arg, double when, int, bool cbdata)
3586+{}
3587+int64_t
3588+MemObject::endOffset() const
3589+{ return 0; }
3590+/* end of stubs */
3591+
3592+// test string
3593+static char fox[]="The quick brown fox jumped over the lazy dog";
3594+static char fox1[]="The quick brown fox ";
3595+static char fox2[]="jumped over the lazy dog";
3596+
3597+// TEST: globals variables (default/empty and with contents) are
3598+// created outside and before any unit tests and memory subsystem
3599+// initialization. Check for correct constructor operation.
3600+SBuf empty_sbuf;
3601+SBuf literal("The quick brown fox jumped over the lazy dog");
3602+
3603+void
3604+testSBuf::testSBufConstructDestruct()
3605+{
3606+ /* NOTE: Do not initialize memory here because we need
3607+ * to test correct operation before and after Mem::Init
3608+ */
3609+
3610+ // XXX: partial demo below of how to do constructor unit-test. use scope to ensure each test
3611+ // is working on local-scope variables constructed fresh for the test, and destructed when
3612+ // scope exists. use nested scopes to test destructor affects on copied data (MemBlob etc)
3613+
3614+ // TEST: default constructor (implicit destructor non-crash test)
3615+ // test accessors on empty SBuf.
3616+ {
3617+ SBuf s1;
3618+ CPPUNIT_ASSERT_EQUAL(s1.length(),0);
3619+ CPPUNIT_ASSERT_EQUAL(s1,SBuf(""));
3620+ CPPUNIT_ASSERT_EQUAL(s1,empty_sbuf);
3621+ CPPUNIT_ASSERT(0==strcmp("",s1.c_str()));
3622+ }
3623+
3624+ // TEST: copy-construct NULL string (implicit destructor non-crash test)
3625+ {
3626+ SBuf s1(NULL);
3627+ CPPUNIT_ASSERT_EQUAL(s1.length(),0);
3628+ CPPUNIT_ASSERT_EQUAL(s1,SBuf(""));
3629+ CPPUNIT_ASSERT_EQUAL(s1,empty_sbuf);
3630+ CPPUNIT_ASSERT(0==strcmp("",s1.c_str()));
3631+ }
3632+
3633+ // TEST: copy-construct empty string (implicit destructor non-crash test)
3634+ {
3635+ SBuf s1("");
3636+ CPPUNIT_ASSERT_EQUAL(s1.length(),0);
3637+ CPPUNIT_ASSERT_EQUAL(s1,SBuf(""));
3638+ CPPUNIT_ASSERT_EQUAL(s1,empty_sbuf);
3639+ CPPUNIT_ASSERT(0==strcmp("",s1.c_str()));
3640+ }
3641+
3642+ // TEST: copy-construct from a SBuf
3643+ {
3644+ SBuf s1(empty_sbuf);
3645+ CPPUNIT_ASSERT_EQUAL(s1.length(),0);
3646+ CPPUNIT_ASSERT_EQUAL(s1,SBuf(""));
3647+ CPPUNIT_ASSERT_EQUAL(s1,empty_sbuf);
3648+ CPPUNIT_ASSERT(0==strcmp("",s1.c_str()));
3649+
3650+ SBuf s5(literal);
3651+ CPPUNIT_ASSERT_EQUAL(s5,literal);
3652+ SBuf s6(fox);
3653+ CPPUNIT_ASSERT_EQUAL(s6,literal);
3654+ // XXX: other state checks. expected result of calling any state accessor on s4 ?
3655+ }
3656+
3657+ // TEST: check that COW doesn't happen upon copy-construction
3658+ {
3659+ SBuf s1(empty_sbuf), s2(s1);
3660+ CPPUNIT_ASSERT_EQUAL(s1.rawContent(), s2.rawContent());
3661+ SBuf s3(literal), s4(literal);
3662+ CPPUNIT_ASSERT_EQUAL(s3.rawContent(), s4.rawContent());
3663+ }
3664+
3665+ // TEST: sub-string copy
3666+ {
3667+ SBuf s1=SBuf(fox,4), s2(fox);
3668+ SBuf s3=s2.substr(4,s2.length()); //n is out-of-bounds
3669+ CPPUNIT_ASSERT_EQUAL(s1,s3);
3670+ SBuf s4=SBuf(fox,0,4);
3671+ s3=s2.substr(0,4);
3672+ CPPUNIT_ASSERT_EQUAL(s4,s3);
3673+ }
3674+
3675+ // TEST: go via SquidString adapters.
3676+ {
3677+ String str(fox);
3678+ SBuf s1(str);
3679+ CPPUNIT_ASSERT_EQUAL(s1,literal);
3680+ }
3681+}
3682+
3683+void
3684+testSBuf::testSBufConstructDestructAfterMemInit()
3685+{
3686+ Mem::Init();
3687+ testSBufConstructDestruct();
3688+
3689+// XXX: or perhapse ...
3690+// repeat all of the tests inside testSBufConstructDestructBeforeMemInit()
3691+// with additional checks on Mem usage stats after each operation ??
3692+}
3693+
3694+void
3695+testSBuf::testEqualityTest()
3696+{
3697+ SBuf s1(fox),s2(fox);
3698+ CPPUNIT_ASSERT_EQUAL(s1,s1); //self-equality
3699+ CPPUNIT_ASSERT_EQUAL(s1,s2); //same contents
3700+ s2.assign("The quick brown fox jumped over the lazy doe");
3701+ CPPUNIT_ASSERT(!(s1 == s2)); //same length, different contents
3702+ s2.assign("foo");
3703+ CPPUNIT_ASSERT(!(s1 == s2)); //different length and contents
3704+ CPPUNIT_ASSERT(s1 != s2); //while we're ready, let's test inequality
3705+ s2.clear();
3706+ CPPUNIT_ASSERT(!(s1 == s2)); //null and not-null
3707+ CPPUNIT_ASSERT(s1 != s2); //while we're ready, let's test inequality
3708+ s1.clear();
3709+ CPPUNIT_ASSERT_EQUAL(s1,s2); //null and null
3710+}
3711+
3712+void
3713+testSBuf::testAppendSBuf()
3714+{
3715+ SBuf s1(fox1),s2(fox2);
3716+ s1.append(s2);
3717+ CPPUNIT_ASSERT_EQUAL(s1,literal);
3718+}
3719+
3720+void
3721+testSBuf::testPrintf()
3722+{
3723+ SBuf s1,s2;
3724+ s1.Printf("%s:%d:%03.3f","fox",10,12345.67);
3725+ s2.assign("fox:10:12345.670");
3726+ CPPUNIT_ASSERT_EQUAL(s1,s2);
3727+}
3728+
3729+void
3730+testSBuf::testAppendCString()
3731+{
3732+ SBuf s1(fox1);
3733+ s1.append(fox2);
3734+ CPPUNIT_ASSERT_EQUAL(s1,literal);
3735+}
3736+
3737+void
3738+testSBuf::testAppendStdString()
3739+{
3740+ SBuf s1(fox1);
3741+ std::string str(fox2);
3742+ s1.append(str);
3743+ CPPUNIT_ASSERT_EQUAL(s1,literal);
3744+}
3745+
3746+void
3747+testSBuf::testAppendf()
3748+{
3749+ SBuf s1,s2;
3750+ s1.appendf("%s:%d:%03.2f",fox,1234,1234.56);
3751+ s2.assign("The quick brown fox jumped over the lazy dog:1234:1234.56");
3752+ CPPUNIT_ASSERT_EQUAL(s1,s2);
3753+}
3754+
3755+void
3756+testSBuf::testDumpStats()
3757+{
3758+ SBuf::GetStats().dump(std::cout);
3759+ MemBlob::GetStats().dump(std::cout);
3760+ std::cout << "sizeof(SBuf): " << sizeof(SBuf) << std::endl;
3761+ std::cout << "sizeof(MemBlob): " << sizeof(MemBlob) << std::endl;
3762+}
3763+
3764+void
3765+testSBuf::testSubscriptOp()
3766+{
3767+ SBuf chg(literal);
3768+ CPPUNIT_ASSERT_EQUAL(chg[5],'u');
3769+ chg.setAt(5,'e');
3770+ CPPUNIT_ASSERT_EQUAL(literal[5],'u');
3771+ CPPUNIT_ASSERT_EQUAL(chg[5],'e');
3772+// std::cout << chg << std::endl << empty_sbuf << std::endl ;
3773+}
3774+
3775+// note: can't use cppunit's CPPUNIT_TEST_EXCEPTION because TextException asserts, and
3776+// so the test can't be properly completed.
3777+void
3778+testSBuf::testSubscriptOpFail()
3779+{
3780+ char c;
3781+ c=literal.at(1234); //out of bounds
3782+ //notreached
3783+ std::cout << c << std::endl;
3784+}
3785+
3786+static int sign(int v)
3787+{
3788+ if (v < 0)
3789+ return -1;
3790+ if (v>0)
3791+ return 1;
3792+ return 0;
3793+}
3794+
3795+void
3796+testSBuf::testComparisons()
3797+{
3798+ //same length
3799+ SBuf s1("foo"),s2("foe");
3800+ CPPUNIT_ASSERT(s1.cmp(s2)>0);
3801+ CPPUNIT_ASSERT(s1.casecmp(s2)>0);
3802+ CPPUNIT_ASSERT(s2.cmp(s1)<0);
3803+ CPPUNIT_ASSERT_EQUAL(0,s1.cmp(s2,2));
3804+ CPPUNIT_ASSERT_EQUAL(0,s1.casecmp(s2,2));
3805+ CPPUNIT_ASSERT(s1 > s2);
3806+ CPPUNIT_ASSERT(s2 < s1);
3807+ CPPUNIT_ASSERT_EQUAL(sign(s1.cmp(s2)),sign(strcmp(s1.c_str(),s2.c_str())));
3808+ //different lengths
3809+ s1.assign("foo");
3810+ s2.assign("foof");
3811+ CPPUNIT_ASSERT(s1.cmp(s2)<0);
3812+ CPPUNIT_ASSERT_EQUAL(sign(s1.cmp(s2)),sign(strcmp(s1.c_str(),s2.c_str())));
3813+ CPPUNIT_ASSERT(s1 < s2);
3814+ // specifying the max-length and overhanging size
3815+ CPPUNIT_ASSERT_EQUAL(1,SBuf("foolong").casecmp(SBuf("foo"), 5));
3816+ // case-insensive comaprison
3817+ s1 = "foo";
3818+ s2 = "fOo";
3819+ CPPUNIT_ASSERT_EQUAL(0,s1.casecmp(s2));
3820+ CPPUNIT_ASSERT_EQUAL(0,s1.casecmp(s2,2));
3821+ // \0-clenliness test
3822+ s1.assign("f\0oo",0,4);
3823+ s2.assign("f\0Oo",0,4);
3824+ CPPUNIT_ASSERT_EQUAL(1,s1.cmp(s2));
3825+ CPPUNIT_ASSERT_EQUAL(0,s1.casecmp(s2));
3826+ CPPUNIT_ASSERT_EQUAL(0,s1.casecmp(s2,3));
3827+}
3828+
3829+void
3830+testSBuf::testConsume()
3831+{
3832+ SBuf s1(literal),s2,s3;
3833+ s2=s1.consume(4);
3834+ s3.assign("The ");
3835+ CPPUNIT_ASSERT_EQUAL(s2,s3);
3836+ s3.assign("quick brown fox jumped over the lazy dog");
3837+ CPPUNIT_ASSERT_EQUAL(s1,s3);
3838+ s1.consume(40);
3839+ CPPUNIT_ASSERT_EQUAL(s1,SBuf());
3840+}
3841+
3842+void
3843+testSBuf::testRawContent()
3844+{
3845+ SBuf s1(literal);
3846+ SBuf s2(s1);
3847+ s2.append("foo");
3848+ const char *foo;
3849+ foo = s1.rawContent();
3850+ CPPUNIT_ASSERT(strncmp(fox,foo,s1.length())==0);
3851+ foo = s1.c_str();
3852+ CPPUNIT_ASSERT(!strcmp(fox,foo));
3853+}
3854+
3855+void
3856+testSBuf::testRawSpace()
3857+{
3858+ SBuf s1(literal);
3859+ SBuf s2(fox1);
3860+ char *rb=s2.rawSpace(strlen(fox2)+1);
3861+ strcat(rb,fox2);
3862+ CPPUNIT_ASSERT_EQUAL(s1,s2);
3863+}
3864+
3865+void
3866+testSBuf::testChop()
3867+{
3868+ SBuf s1(literal),s2;
3869+ s1.chop(4,5);
3870+ s2.assign("quick");
3871+ CPPUNIT_ASSERT_EQUAL(s1,s2);
3872+ s1=literal;
3873+ s2.clear();
3874+ s1.chop(5,0);
3875+ CPPUNIT_ASSERT_EQUAL(s1,s2);
3876+}
3877+
3878+void
3879+testSBuf::testChomp()
3880+{
3881+ SBuf s1("complete string");
3882+ SBuf s2(s1);
3883+ s2.trim(SBuf(" ,"));
3884+ CPPUNIT_ASSERT_EQUAL(s1,s2);
3885+ s2.assign(" complete string ,");
3886+ s2.trim(SBuf(" ,"));
3887+ CPPUNIT_ASSERT_EQUAL(s1,s2);
3888+ s1.assign(", complete string ,");
3889+ s2=s1;
3890+ s2.trim(SBuf(" "));
3891+ CPPUNIT_ASSERT_EQUAL(s1,s2);
3892+}
3893+
3894+void
3895+testSBuf::testSubstr()
3896+{
3897+ SBuf s1(literal),s2,s3;
3898+ s2=s1.substr(4,5);
3899+ s3.assign("quick");
3900+ CPPUNIT_ASSERT_EQUAL(s2,s3);
3901+ s1.chop(4,5);
3902+ CPPUNIT_ASSERT_EQUAL(s1,s2);
3903+}
3904+
3905+void
3906+testSBuf::testFindChar()
3907+{
3908+ const char *alphabet="abcdefghijklmnopqrstuvwxyz";
3909+ SBuf s1(alphabet);
3910+ SBuf::size_type idx;
3911+ idx=s1.find('d');
3912+ CPPUNIT_ASSERT(idx == 3);
3913+ CPPUNIT_ASSERT(s1[idx]=='d');
3914+ idx=s1.find(' '); //fails
3915+ CPPUNIT_ASSERT(idx==SBuf::npos);
3916+ idx=s1.find('e',5);
3917+ CPPUNIT_ASSERT(idx==SBuf::npos);
3918+ idx=s1.rfind('x',s1.length()-4);
3919+ CPPUNIT_ASSERT(idx==SBuf::npos);
3920+}
3921+
3922+void
3923+testSBuf::testFindSBuf()
3924+{
3925+ SBuf haystack(literal),afox("fox"),foobar("foobar"),foe("foe"), dog("dog");
3926+ SBuf toolong(literal), g;
3927+ //very long string matching at the end
3928+ toolong.append(literal).append(literal).append(literal).append(literal);
3929+ SBuf::size_type idx;
3930+ idx=haystack.find(afox);
3931+ CPPUNIT_ASSERT_EQUAL(16,idx);
3932+ idx=haystack.find(foobar); //fails
3933+ CPPUNIT_ASSERT(idx==SBuf::npos);
3934+ idx=haystack.find(foe); //fails
3935+ CPPUNIT_ASSERT(idx==SBuf::npos);
3936+ idx=haystack.find(foe);
3937+ CPPUNIT_ASSERT(idx==SBuf::npos);
3938+ idx=haystack.find(dog);
3939+ CPPUNIT_ASSERT_EQUAL(haystack.length()-dog.length(),idx);
3940+ dog.append("foo");
3941+ idx=haystack.find(dog);
3942+ CPPUNIT_ASSERT(idx==SBuf::npos);
3943+ idx=haystack.find(toolong);
3944+ CPPUNIT_ASSERT(SBuf::npos==idx); //consistent with std::string
3945+ g="g"; //match at the last char
3946+ idx=haystack.find(g);
3947+ CPPUNIT_ASSERT_EQUAL(43,idx);
3948+ CPPUNIT_ASSERT_EQUAL('g',haystack[idx]);
3949+}
3950+
3951+void
3952+testSBuf::testRFindChar()
3953+{
3954+ SBuf s1(literal);
3955+ SBuf::size_type idx;
3956+ idx=s1.rfind(' ');
3957+ CPPUNIT_ASSERT_EQUAL(40,idx);
3958+ CPPUNIT_ASSERT_EQUAL(' ',s1[idx]);
3959+}
3960+
3961+void
3962+testSBuf::testRFindSBuf()
3963+{
3964+ SBuf haystack(literal),afox("fox");
3965+ SBuf goobar("goobar");
3966+ SBuf::size_type idx;
3967+
3968+ // corner case: search for a zero-length SBuf
3969+ idx=haystack.rfind(SBuf(""));
3970+ CPPUNIT_ASSERT_EQUAL(haystack.length(),idx);
3971+
3972+ // corner case: search for a needle longer than the haystack
3973+ idx=afox.rfind(SBuf(" "));
3974+ CPPUNIT_ASSERT(idx==SBuf::npos);
3975+
3976+ idx=haystack.rfind(SBuf("fox"));
3977+ CPPUNIT_ASSERT_EQUAL(16,idx);
3978+
3979+ // needle not found, no match for first char
3980+ idx=goobar.rfind(SBuf("foo"));
3981+ CPPUNIT_ASSERT(idx==SBuf::npos);
3982+
3983+ // needle not found, match for first char but no match for SBuf
3984+ idx=haystack.rfind(SBuf("foe"));
3985+ CPPUNIT_ASSERT(idx==SBuf::npos);
3986+
3987+ SBuf g("g"); //match at the last char
3988+ idx=haystack.rfind(g);
3989+ CPPUNIT_ASSERT_EQUAL(43,idx);
3990+ CPPUNIT_ASSERT_EQUAL('g',haystack[idx]);
3991+
3992+ idx=haystack.rfind(SBuf("The"));
3993+ CPPUNIT_ASSERT_EQUAL(0,idx);
3994+
3995+ haystack.append("The");
3996+ idx=haystack.rfind(SBuf("The"));
3997+ CPPUNIT_ASSERT_EQUAL(44,idx);
3998+
3999+ //partial match
4000+ haystack="The quick brown fox";
4001+ SBuf needle("foxy lady");
4002+ idx=haystack.rfind(needle);
4003+ CPPUNIT_ASSERT(idx==SBuf::npos);
4004+}
4005+
4006+void
4007+testSBuf::testSBufLength()
4008+{
4009+ SBuf s(fox);
4010+ CPPUNIT_ASSERT((size_t)s.length()==strlen(fox));
4011+}
4012+
4013+void
4014+testSBuf::testScanf()
4015+{
4016+ SBuf s1;
4017+ char s[128];
4018+ int i;
4019+ float f;
4020+ int rv;
4021+ s1.assign("string , 123 , 123.50");
4022+ rv=s1.scanf("%s , %d , %f",s,&i,&f);
4023+ CPPUNIT_ASSERT(3 == rv);
4024+ CPPUNIT_ASSERT(0 == strcmp(s,"string"));
4025+ CPPUNIT_ASSERT(i == 123);
4026+ CPPUNIT_ASSERT(f == 123.5);
4027+}
4028+
4029+void testSBuf::testCopy()
4030+{
4031+ char buf[40]; //shorter than literal()
4032+ SBuf s(fox1),s2;
4033+ CPPUNIT_ASSERT(s.copy(buf,40)==s.length());
4034+ CPPUNIT_ASSERT(strncmp(s.rawContent(),buf,s.length())==0);
4035+ s=literal;
4036+ CPPUNIT_ASSERT(s.copy(buf,40)==40);
4037+ s2.assign(buf,0,40);
4038+ s.chop(0,40);
4039+ CPPUNIT_ASSERT(s==s2);
4040+}
4041+
4042+// XXX: please split each class into a separate unit-test .cc / even if they share a binary.
4043+// rule-of-thumb guideline for layering is 'one class Foo -> one Foo.cc, one Foo.cc -> one testFoo.cc'
4044+
4045+static int sbuf_tokens_number=9;
4046+static SBuf tokens[]={
4047+ SBuf("The",0,3), SBuf("quick",0,5), SBuf("brown",0,5), SBuf("fox",0,3),
4048+ SBuf("jumped",0,6), SBuf("over",0,4), SBuf("the",0,3), SBuf("lazy",0,4),
4049+ SBuf("dog",0,3)
4050+};
4051+
4052+void testSBuf::testSBufTokenizer()
4053+{
4054+ int j=0;
4055+ SBuf s;
4056+ for (SBufTokenizer st(literal,SBuf(" ",0,1)); !st.atEnd(); st.next()) {
4057+ s=st.token();
4058+ CPPUNIT_ASSERT(s==tokens[j]);
4059+ j++;
4060+ }
4061+ CPPUNIT_ASSERT(j==9);
4062+}
4063+
4064+void testSBuf::testStringOps()
4065+{
4066+ SBuf sng(literal),
4067+ ref("the quick brown fox jumped over the lazy dog");
4068+ sng=sng.toLower();
4069+ CPPUNIT_ASSERT_EQUAL(ref,sng);
4070+ sng=literal;
4071+ CPPUNIT_ASSERT_EQUAL(0,sng.compare(ref,caseInsensitive));
4072+}
4073+
4074+void testSBuf::testGrow()
4075+{
4076+ SBuf t;
4077+ t.assign("foo");
4078+ const char *ref=t.rawContent();
4079+ t.reserveCapacity(10240);
4080+ const char *match=t.rawContent();
4081+ CPPUNIT_ASSERT(match!=ref);
4082+ ref=match;
4083+ t.append(literal).append(literal).append(literal).append(literal).append(literal);
4084+ t.append(t).append(t).append(t).append(t).append(t);
4085+ CPPUNIT_ASSERT(match==ref);
4086+}
4087+
4088+void testSBuf::testStartsWith()
4089+{
4090+ static SBuf casebuf("THE QUICK");
4091+ CPPUNIT_ASSERT(literal.startsWith(SBuf(fox1)));
4092+ CPPUNIT_ASSERT(!SBuf("The quick brown").startsWith(SBuf(fox1))); //too short
4093+ CPPUNIT_ASSERT(!literal.startsWith(SBuf(fox2))); //different contents
4094+
4095+ // case-insensitive checks
4096+ CPPUNIT_ASSERT(literal.startsWith(casebuf,caseInsensitive));
4097+ casebuf=SBuf(fox1).toUpper();
4098+ CPPUNIT_ASSERT(literal.startsWith(casebuf,caseInsensitive));
4099+ CPPUNIT_ASSERT(literal.startsWith(SBuf(fox1),caseInsensitive));
4100+ casebuf = "tha quick";
4101+ CPPUNIT_ASSERT_EQUAL(false,literal.startsWith(casebuf,caseInsensitive));
4102+}
4103+
4104+void testSBuf::testSBufList()
4105+{
4106+ SBufList foo;
4107+ for (int j=0; j<sbuf_tokens_number; ++j)
4108+ foo.add(tokens[j]);
4109+ CPPUNIT_ASSERT(foo.isMember(SBuf("fox")));
4110+ CPPUNIT_ASSERT(foo.isMember(SBuf("Fox"),caseInsensitive));
4111+ CPPUNIT_ASSERT(!foo.isMember(SBuf("garble")));
4112+ CPPUNIT_ASSERT(foo.isPrefix(SBuf("qui")));
4113+ CPPUNIT_ASSERT(foo.isPrefix(SBuf("qUi"),caseInsensitive));
4114+ CPPUNIT_ASSERT(!foo.isPrefix(SBuf("qUa"),caseInsensitive));
4115+}
4116+
4117+void testSBuf::testBaseName()
4118+{
4119+ SBuf totest("/foo/bar/gazonk");
4120+ CPPUNIT_ASSERT_EQUAL(BaseName(totest),SBuf("gazonk"));
4121+ CPPUNIT_ASSERT_EQUAL(BaseName(totest,'.'),totest);
4122+}
4123+
4124+void testSBuf::testSBufStream()
4125+{
4126+ SBuf b("const.string, int 10 and a float 10.5");
4127+ SBufStream ss;
4128+ ss << "const.string, int " << 10 << " and a float " << 10.5;
4129+ SBuf o=ss.buf();
4130+ CPPUNIT_ASSERT_EQUAL(b,o);
4131+ ss.clearBuf();
4132+ o=ss.buf();
4133+ CPPUNIT_ASSERT_EQUAL(SBuf(),o);
4134+ SBuf f1(fox1);
4135+ SBufStream ss2(f1);
4136+ ss2 << fox2;
4137+ CPPUNIT_ASSERT_EQUAL(ss2.buf(),literal);
4138+ CPPUNIT_ASSERT_EQUAL(f1,SBuf(fox1));
4139+}
4140+
4141+void testSBuf::testFindFirstOf()
4142+{
4143+ SBuf haystack(literal);
4144+ SBuf::size_type idx;
4145+
4146+ // not found
4147+ idx=haystack.find_first_of(SBuf("ADHRWYP"));
4148+ CPPUNIT_ASSERT(idx==SBuf::npos);
4149+
4150+ // found at beginning
4151+ idx=haystack.find_first_of(SBuf("THANDF"));
4152+ CPPUNIT_ASSERT_EQUAL(0,idx);
4153+
4154+ //found at end of haystack
4155+ idx=haystack.find_first_of(SBuf("QWERYVg"));
4156+ CPPUNIT_ASSERT_EQUAL(haystack.length()-1,idx);
4157+
4158+ //found in the middle of haystack
4159+ idx=haystack.find_first_of(SBuf("QWERqYV"));
4160+ CPPUNIT_ASSERT_EQUAL(4,idx);
4161+}
4162+
4163+void testSBuf::testAutoFind()
4164+{
4165+ SBufFindTest test;
4166+ test.run();
4167+}
4168
4169=== added file 'src/tests/testSBuf.h'
4170--- src/tests/testSBuf.h 1970-01-01 00:00:00 +0000
4171+++ src/tests/testSBuf.h 2013-07-04 15:56:30 +0000
4172@@ -0,0 +1,92 @@
4173+#ifndef SQUID_SRC_TEST_TESTSBUF_H
4174+#define SQUID_SRC_TEST_TESTSBUF_H
4175+
4176+#include <cppunit/extensions/HelperMacros.h>
4177+
4178+#include "OutOfBoundsException.h"
4179+
4180+/*
4181+ * test the SBuf functionalities
4182+ */
4183+
4184+class testSBuf : public CPPUNIT_NS::TestFixture
4185+{
4186+ CPPUNIT_TEST_SUITE( testSBuf );
4187+ CPPUNIT_TEST( testSBufConstructDestruct );
4188+ CPPUNIT_TEST( testSBufConstructDestructAfterMemInit );
4189+ CPPUNIT_TEST( testSBufLength );
4190+ CPPUNIT_TEST( testEqualityTest );
4191+ CPPUNIT_TEST( testStartsWith );
4192+ CPPUNIT_TEST( testAppendSBuf );
4193+ CPPUNIT_TEST( testAppendCString );
4194+ CPPUNIT_TEST( testAppendStdString );
4195+ CPPUNIT_TEST( testAppendf );
4196+ CPPUNIT_TEST( testSubscriptOp );
4197+ CPPUNIT_TEST_EXCEPTION( testSubscriptOpFail , OutOfBoundsException );
4198+ CPPUNIT_TEST( testComparisons );
4199+ CPPUNIT_TEST( testConsume );
4200+ CPPUNIT_TEST( testRawContent );
4201+ //CPPUNIT_TEST( testRawSpace );
4202+ CPPUNIT_TEST( testChop );
4203+ CPPUNIT_TEST( testChomp );
4204+ CPPUNIT_TEST( testSubstr );
4205+ CPPUNIT_TEST( testFindChar );
4206+ CPPUNIT_TEST( testFindSBuf );
4207+ CPPUNIT_TEST( testRFindChar );
4208+ CPPUNIT_TEST( testRFindSBuf );
4209+ CPPUNIT_TEST( testFindFirstOf );
4210+ CPPUNIT_TEST( testPrintf );
4211+ CPPUNIT_TEST( testScanf );
4212+ CPPUNIT_TEST( testCopy );
4213+ CPPUNIT_TEST( testSBufTokenizer );
4214+ CPPUNIT_TEST( testStringOps );
4215+ CPPUNIT_TEST( testGrow );
4216+ CPPUNIT_TEST( testSBufList );
4217+ CPPUNIT_TEST( testBaseName );
4218+ CPPUNIT_TEST( testSBufStream );
4219+ CPPUNIT_TEST( testAutoFind );
4220+
4221+// CPPUNIT_TEST( testDumpStats ); //fake test, to print alloc stats
4222+
4223+ CPPUNIT_TEST_SUITE_END();
4224+protected:
4225+ void commonInit();
4226+ void testSBufConstructDestruct();
4227+ void testSBufConstructDestructAfterMemInit();
4228+ void testEqualityTest();
4229+ void testAppendSBuf();
4230+ void testAppendCString();
4231+ void testAppendStdString();
4232+ void testAppendf();
4233+ void testPrintf();
4234+ void testScanf();
4235+ void testSubscriptOp();
4236+ void testSubscriptOpFail();
4237+ void testDumpStats();
4238+ void testComparisons();
4239+ void testConsume();
4240+ void testRawContent();
4241+ void testRawSpace();
4242+ void testChop();
4243+ void testChomp();
4244+ void testSubstr();
4245+ void testTailCopy();
4246+ void testSBufLength();
4247+ void testFindChar();
4248+ void testFindSBuf();
4249+ void testRFindChar();
4250+ void testRFindSBuf();
4251+ void testSearchFail();
4252+ void testCopy();
4253+ void testSBufTokenizer();
4254+ void testStringOps();
4255+ void testGrow();
4256+ void testStartsWith();
4257+ void testSBufList();
4258+ void testBaseName();
4259+ void testSBufStream();
4260+ void testFindFirstOf();
4261+ void testAutoFind();
4262+};
4263+
4264+#endif

Subscribers

People subscribed via source and target branches