]> git.ipfire.org Git - thirdparty/squid.git/blob - src/sbuf/SBuf.h
cb5e12ad34511ec9ab4674034e63ca12410d490b
[thirdparty/squid.git] / src / sbuf / SBuf.h
1 /*
2 * Copyright (C) 1996-2019 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 /* DEBUG: section 24 SBuf */
10
11 #ifndef SQUID_SBUF_H
12 #define SQUID_SBUF_H
13
14 #include "base/InstanceId.h"
15 #include "base/TextException.h"
16 #include "Debug.h"
17 #include "globals.h"
18 #include "sbuf/forward.h"
19 #include "sbuf/MemBlob.h"
20 #include "sbuf/Stats.h"
21
22 #include <climits>
23 #include <iosfwd>
24 #include <iterator>
25 #if HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
28
29 /* SBuf placeholder for printf */
30 #ifndef SQUIDSBUFPH
31 #define SQUIDSBUFPH "%.*s"
32 #define SQUIDSBUFPRINT(s) (s).plength(),(s).rawContent()
33 #endif /* SQUIDSBUFPH */
34
35 // TODO: move within SBuf and rename
36 typedef enum {
37 caseSensitive,
38 caseInsensitive
39 } SBufCaseSensitive;
40
41 class CharacterSet;
42
43 /** Forward input const_iterator for SBufs
44 *
45 * Please note that any operation on the underlying SBuf may invalidate
46 * all iterators over it, resulting in undefined behavior by them.
47 */
48 class SBufIterator : public std::iterator<std::input_iterator_tag, char>
49 {
50 public:
51 friend class SBuf;
52 typedef MemBlob::size_type size_type;
53 bool operator==(const SBufIterator &s) const;
54 bool operator!=(const SBufIterator &s) const;
55
56 const char &operator*() const { return *iter; }
57 SBufIterator& operator++() { ++iter; return *this; }
58
59 protected:
60 SBufIterator(const SBuf &, size_type);
61
62 const char *iter = nullptr;
63 };
64
65 /** Reverse input const_iterator for SBufs
66 *
67 * Please note that any operation on the underlying SBuf may invalidate
68 * all iterators over it, resulting in undefined behavior by them.
69 */
70 class SBufReverseIterator : public SBufIterator
71 {
72 friend class SBuf;
73 public:
74 SBufReverseIterator& operator++() { --iter; return *this;}
75 const char &operator*() const { return *(iter-1); }
76 protected:
77 SBufReverseIterator(const SBuf &s, size_type sz) : SBufIterator(s,sz) {}
78 };
79
80 /**
81 * A String or Buffer.
82 * Features: refcounted backing store, cheap copy and sub-stringing
83 * operations, copy-on-write to isolate change operations to each instance.
84 * Where possible, we're trying to mimic std::string's interface.
85 */
86 class SBuf
87 {
88 public:
89 typedef MemBlob::size_type size_type;
90 typedef SBufIterator const_iterator;
91 typedef SBufReverseIterator const_reverse_iterator;
92 static const size_type npos = 0xffffffff; // max(uint32_t)
93
94 /// Maximum size of a SBuf. By design it MUST be < MAX(size_type)/2. Currently 256Mb.
95 static const size_type maxSize = 0xfffffff;
96
97 /// create an empty (zero-size) SBuf
98 SBuf();
99 SBuf(const SBuf &S);
100 SBuf(SBuf&& S) : store_(std::move(S.store_)), off_(S.off_), len_(S.len_) {
101 ++stats.moves;
102 S.store_ = nullptr; //RefCount supports nullptr, and S is about to be destructed
103 S.off_ = S.len_ = 0;
104 }
105
106 /** Constructor: import c-style string
107 *
108 * Create a new SBuf containing a COPY of the contents of the
109 * c-string
110 * \param S the c string to be copied
111 * \param n how many bytes to import into the SBuf. If it is npos
112 * or unspecified, imports to end-of-cstring
113 * \note it is the caller's responsibility not to go out of bounds
114 * \note bounds is 0 <= pos < length(); caller must pay attention to signedness
115 */
116 explicit SBuf(const char *S, size_type n);
117 explicit SBuf(const char *S);
118
119 /// Constructor: import std::string. Contents are copied.
120 explicit SBuf(const std::string &s);
121
122 ~SBuf();
123
124 /** Explicit assignment.
125 *
126 * Current SBuf will share backing store with the assigned one.
127 */
128 SBuf& assign(const SBuf &S);
129
130 /** Assignment operator.
131 *
132 * Current SBuf will share backing store with the assigned one.
133 */
134 SBuf& operator =(const SBuf & S) {return assign(S);}
135 SBuf& operator =(SBuf &&S) {
136 ++stats.moves;
137 if (this != &S) {
138 store_ = std::move(S.store_);
139 off_ = S.off_;
140 len_ = S.len_;
141 S.store_ = NULL; //RefCount supports NULL, and S is about to be destructed
142 S.off_ = 0;
143 S.len_ = 0;
144 }
145 return *this;
146 }
147
148 /** Import a c-string into a SBuf, copying the data.
149 *
150 * It is the caller's duty to free the imported string, if needed.
151 * \param S the c string to be copied
152 * \param n how many bytes to import into the SBuf. If it is npos
153 * or unspecified, imports to end-of-cstring
154 * \note it is the caller's responsibility not to go out of bounds
155 * \note to assign a std::string use the pattern:
156 * assign(stdstr.data(), stdstd.length())
157 */
158 SBuf& assign(const char *S, size_type n);
159 SBuf& assign(const char *S) {return assign(S,npos);}
160
161 /** Assignment operator. Copy a NULL-terminated c-style string into a SBuf.
162 *
163 * Copy a c-style string into a SBuf. Shortcut for SBuf.assign(S)
164 * It is the caller's duty to free the imported string, if needed.
165 * \note not \0-clean
166 */
167 SBuf& operator =(const char *S) {return assign(S);}
168
169 /** reset the SBuf as if it was just created.
170 *
171 * Resets the SBuf to empty, memory is freed lazily.
172 */
173 void clear();
174
175 /** Append operation
176 *
177 * Append the supplied SBuf to the current one; extend storage as needed.
178 */
179 SBuf& append(const SBuf & S);
180
181 /// Append a single character. The character may be NUL (\0).
182 SBuf& append(const char c);
183
184 /** Append operation for C-style strings.
185 *
186 * Append the supplied c-string to the SBuf; extend storage
187 * as needed.
188 *
189 * \param S the c string to be copied. Can be NULL.
190 * \param Ssize how many bytes to import into the SBuf. If it is npos
191 * or unspecified, imports to end-of-cstring. If S is NULL,
192 * Ssize is ignored.
193 * \note to append a std::string use the pattern
194 * cstr_append(stdstr.data(), stdstd.length())
195 */
196 SBuf& append(const char * S, size_type Ssize);
197 SBuf& append(const char * S) { return append(S,npos); }
198
199 /** Assignment operation with printf(3)-style definition
200 * \note arguments may be evaluated more than once, be careful
201 * of side-effects
202 */
203 SBuf& Printf(const char *fmt, ...);
204
205 /** Append operation with printf-style arguments
206 * \note arguments may be evaluated more than once, be careful
207 * of side-effects
208 */
209 SBuf& appendf(const char *fmt, ...);
210
211 /** Append operation, with vsprintf(3)-style arguments.
212 * \note arguments may be evaluated more than once, be careful
213 * of side-effects
214 */
215 SBuf& vappendf(const char *fmt, va_list vargs);
216
217 /// print the SBuf contents to the supplied ostream
218 std::ostream& print(std::ostream &os) const;
219
220 /** print SBuf contents and debug information about the SBuf to an ostream
221 *
222 * Debug function, dumps to a stream informations on the current SBuf,
223 * including low-level details and statistics.
224 */
225 std::ostream& dump(std::ostream &os) const;
226
227 /** random-access read to any char within the SBuf
228 *
229 * does not check access bounds. If you need that, use at()
230 */
231 char operator [](size_type pos) const {++stats.getChar; return store_->mem[off_+pos];}
232
233 /** random-access read to any char within the SBuf.
234 *
235 * \throw std::exception when access is out of bounds
236 * \note bounds is 0 <= pos < length(); caller must pay attention to signedness
237 */
238 char at(size_type pos) const {checkAccessBounds(pos); return operator[](pos);}
239
240 /** direct-access set a byte at a specified operation.
241 *
242 * \param pos the position to be overwritten
243 * \param toset the value to be written
244 * \throw std::exception when pos is of bounds
245 * \note bounds is 0 <= pos < length(); caller must pay attention to signedness
246 * \note performs a copy-on-write if needed.
247 */
248 void setAt(size_type pos, char toset);
249
250 /** compare to other SBuf, str(case)cmp-style
251 *
252 * \param isCaseSensitive one of caseSensitive or caseInsensitive
253 * \param n compare up to this many bytes. if npos (default), compare whole SBufs
254 * \retval >0 argument of the call is greater than called SBuf
255 * \retval <0 argument of the call is smaller than called SBuf
256 * \retval 0 argument of the call has the same contents of called SBuf
257 */
258 int compare(const SBuf &S, const SBufCaseSensitive isCaseSensitive, const size_type n) const;
259 int compare(const SBuf &S, const SBufCaseSensitive isCaseSensitive) const {
260 return compare(S, isCaseSensitive, npos);
261 }
262
263 /// shorthand version for compare()
264 inline int cmp(const SBuf &S, const size_type n) const {
265 return compare(S,caseSensitive,n);
266 }
267 inline int cmp(const SBuf &S) const {
268 return compare(S,caseSensitive,npos);
269 }
270
271 /// shorthand version for case-insensitive compare()
272 inline int caseCmp(const SBuf &S, const size_type n) const {
273 return compare(S,caseInsensitive,n);
274 }
275 inline int caseCmp(const SBuf &S) const {
276 return compare(S,caseInsensitive,npos);
277 }
278
279 /// Comparison with a C-string.
280 int compare(const char *s, const SBufCaseSensitive isCaseSensitive, const size_type n) const;
281 int compare(const char *s, const SBufCaseSensitive isCaseSensitive) const {
282 return compare(s,isCaseSensitive,npos);
283 }
284
285 /// Shorthand version for C-string compare().
286 inline int cmp(const char *S, const size_type n) const {
287 return compare(S,caseSensitive,n);
288 }
289 inline int cmp(const char *S) const {
290 return compare(S,caseSensitive,npos);
291 }
292
293 /// Shorthand version for case-insensitive C-string compare().
294 inline int caseCmp(const char *S, const size_type n) const {
295 return compare(S,caseInsensitive,n);
296 }
297 inline int caseCmp(const char *S) const {
298 return compare(S,caseInsensitive,npos);
299 }
300
301 /** check whether the entire supplied argument is a prefix of the SBuf.
302 * \param S the prefix to match against
303 * \param isCaseSensitive one of caseSensitive or caseInsensitive
304 * \retval true argument is a prefix of the SBuf
305 */
306 bool startsWith(const SBuf &S, const SBufCaseSensitive isCaseSensitive = caseSensitive) const;
307
308 bool operator ==(const SBuf & S) const;
309 bool operator !=(const SBuf & S) const;
310 bool operator <(const SBuf &S) const {return (cmp(S) < 0);}
311 bool operator >(const SBuf &S) const {return (cmp(S) > 0);}
312 bool operator <=(const SBuf &S) const {return (cmp(S) <= 0);}
313 bool operator >=(const SBuf &S) const {return (cmp(S) >= 0);}
314
315 /** Consume bytes at the head of the SBuf
316 *
317 * Consume N chars at SBuf head, or to SBuf's end,
318 * whichever is shorter. If more bytes are consumed than available,
319 * the SBuf is emptied
320 * \param n how many bytes to remove; could be zero.
321 * npos (or no argument) means 'to the end of SBuf'
322 * \return a new SBuf containing the consumed bytes.
323 */
324 SBuf consume(size_type n = npos);
325
326 /// gets global statistic informations
327 static const SBufStats& GetStats();
328
329 /** Copy SBuf contents into user-supplied C buffer.
330 *
331 * Export a copy of the SBuf's contents into the user-supplied
332 * buffer, up to the user-supplied-length. No zero-termination is performed
333 * \return num the number of actually-copied chars.
334 */
335 size_type copy(char *dest, size_type n) const;
336
337 /** exports a pointer to the SBuf internal storage.
338 * \warning ACCESSING RAW STORAGE IS DANGEROUS!
339 *
340 * Returns a ead-only pointer to SBuf's content. No terminating null
341 * character is appended (use c_str() for that).
342 * The returned value points to an internal location whose contents
343 * are guaranteed to remain unchanged only until the next call
344 * to a non-constant member function of the SBuf object. Such a
345 * call may be implicit (e.g., when SBuf is destroyed
346 * upon leaving the current context).
347 * This is a very UNSAFE way of accessing the data.
348 * This call never returns NULL.
349 * \see c_str
350 * \note the memory management system guarantees that the exported region
351 * of memory will remain valid if the caller keeps holding
352 * a valid reference to the SBuf object and does not write or append to
353 * it. For example:
354 * \code
355 * SBuf foo("some string");
356 * const char *bar = foo.rawContent();
357 * doSomething(bar); //safe
358 * foo.append(" other string");
359 * doSomething(bar); //unsafe
360 * \endcode
361 */
362 const char* rawContent() const;
363
364 /// \returns a buffer suitable for appending at most `anticipatedSize` bytes
365 /// The buffer must be used "immediately" because it is invalidated by most
366 /// non-constant SBuf method calls, including such calls against other SBuf
367 /// objects that just happen to share the same underlying MemBlob storage!
368 char *rawAppendStart(size_type anticipatedSize);
369
370 /// Updates SBuf metadata to reflect appending `actualSize` bytes to the
371 /// buffer returned by the corresponding rawAppendStart() call. Throws if
372 /// rawAppendStart(actualSize) would have returned a different value now.
373 /// \param start raw buffer previously returned by rawAppendStart()
374 /// \param actualSize the number of appended bytes
375 void rawAppendFinish(const char *start, size_type actualSize);
376
377 /** Obtain how much free space is available in the backing store.
378 *
379 * \note: unless the client just cow()ed, it is not guaranteed that
380 * the free space can be used.
381 */
382 size_type spaceSize() const { return store_->spaceSize(); }
383
384 /** exports a null-terminated reference to the SBuf internal storage.
385 * \warning ACCESSING RAW STORAGE IS DANGEROUS! DO NOT EVER USE
386 * THE RETURNED POINTER FOR WRITING
387 *
388 * The returned value points to an internal location whose contents
389 * are guaranteed to remain unchanged only until the next call
390 * to a non-constant member function of the SBuf object. Such a
391 * call may be implicit (e.g., when SBuf is destroyed
392 * upon leaving the current context).
393 * This is a very UNSAFE way of accessing the data.
394 * This call never returns NULL.
395 * \see rawContent
396 * \note the memory management system guarantees that the exported region
397 * of memory will remain valid will remain valid only if the
398 * caller keeps holding a valid reference to the SBuf object and
399 * does not write or append to it
400 */
401 const char* c_str();
402
403 /// Returns the number of bytes stored in SBuf.
404 size_type length() const {return len_;}
405
406 /** Get the length of the SBuf, as a signed integer
407 *
408 * Compatibility function for printf(3) which requires a signed int
409 * \throw std::exception if buffer length does not fit a signed integer
410 */
411 int plength() const {
412 Must(length() <= INT_MAX);
413 return static_cast<int>(length());
414 }
415
416 /** Check whether the SBuf is empty
417 *
418 * \return true if length() == 0
419 */
420 bool isEmpty() const {return (len_==0);}
421
422 /** Request to guarantee the SBuf's free store space.
423 *
424 * After the reserveSpace request, the SBuf is guaranteed to have at
425 * least minSpace bytes of unused backing store following the currently
426 * used portion and single ownership of the backing store.
427 * \throw std::exception if the user tries to allocate a too big SBuf
428 */
429 void reserveSpace(size_type minSpace) {
430 Must(minSpace <= maxSize);
431 Must(length() <= maxSize - minSpace);
432 reserveCapacity(length()+minSpace);
433 }
434
435 /** Request to guarantee the SBuf's store capacity
436 *
437 * After this method is called, the SBuf is guaranteed to have at least
438 * minCapacity bytes of total buffer size, including the currently-used
439 * portion; it is also guaranteed that after this call this SBuf
440 * has unique ownership of the underlying memory store.
441 * \throw std::exception if the user tries to allocate a too big SBuf
442 */
443 void reserveCapacity(size_type minCapacity);
444
445 /** Accommodate caller's requirements regarding SBuf's storage if possible.
446 *
447 * \return spaceSize(), which may be zero
448 */
449 size_type reserve(const SBufReservationRequirements &requirements);
450
451 /** slicing method
452 *
453 * Removes SBuf prefix and suffix, leaving a sequence of 'n'
454 * bytes starting from position 'pos', first byte is at pos 0.
455 * It is an in-place-modifying version of substr.
456 * \param pos start sub-stringing from this byte. If it is
457 * npos or it is greater than the SBuf length, the SBuf is cleared and
458 * an empty SBuf is returned.
459 * \param n maximum number of bytes of the resulting SBuf.
460 * npos means "to end of SBuf".
461 * if it is 0, the SBuf is cleared and an empty SBuf is returned.
462 * if it overflows the end of the SBuf, it is capped to the end of SBuf
463 * \see substr, trim
464 */
465 SBuf& chop(size_type pos, size_type n = npos);
466
467 /** Remove characters in the toremove set at the beginning, end or both
468 *
469 * \param toremove characters to be removed. Stops chomping at the first
470 * found char not in the set
471 * \param atBeginning if true (default), strips at the beginning of the SBuf
472 * \param atEnd if true (default), strips at the end of the SBuf
473 */
474 SBuf& trim(const SBuf &toRemove, bool atBeginning = true, bool atEnd = true);
475
476 /** Extract a part of the current SBuf.
477 *
478 * Return a fresh a fresh copy of a portion the current SBuf, which is
479 * left untouched. The same parameter convetions apply as for chop.
480 * \see trim, chop
481 */
482 SBuf substr(size_type pos, size_type n = npos) const;
483
484 /** Find first occurrence of character in SBuf
485 *
486 * Returns the index in the SBuf of the first occurrence of char c.
487 * \return npos if the char was not found
488 * \param startPos if specified, ignore any occurrences before that position
489 * if startPos is npos or greater than length() npos is always returned
490 * if startPos is less than zero, it is ignored
491 */
492 size_type find(char c, size_type startPos = 0) const;
493
494 /** Find first occurrence of SBuf in SBuf.
495 *
496 * Returns the index in the SBuf of the first occurrence of the
497 * sequence contained in the str argument.
498 * \param startPos if specified, ignore any occurrences before that position
499 * if startPos is npos or greater than length() npos is always returned
500 * \return npos if the SBuf was not found
501 */
502 size_type find(const SBuf & str, size_type startPos = 0) const;
503
504 /** Find last occurrence of character in SBuf
505 *
506 * Returns the index in the SBuf of the last occurrence of char c.
507 * \return npos if the char was not found
508 * \param endPos if specified, ignore any occurrences after that position.
509 * if npos or greater than length(), the whole SBuf is considered
510 */
511 size_type rfind(char c, size_type endPos = npos) const;
512
513 /** Find last occurrence of SBuf in SBuf
514 *
515 * Returns the index in the SBuf of the last occurrence of the
516 * sequence contained in the str argument.
517 * \return npos if the sequence was not found
518 * \param endPos if specified, ignore any occurrences after that position
519 * if npos or greater than length(), the whole SBuf is considered
520 */
521 size_type rfind(const SBuf &str, size_type endPos = npos) const;
522
523 /** Find first occurrence of character of set in SBuf
524 *
525 * Finds the first occurrence of ANY of the characters in the supplied set in
526 * the SBuf.
527 * \return npos if no character in the set could be found
528 * \param startPos if specified, ignore any occurrences before that position
529 * if npos, then npos is always returned
530 *
531 * TODO: rename to camelCase
532 */
533 size_type findFirstOf(const CharacterSet &set, size_type startPos = 0) const;
534
535 /** Find last occurrence of character of set in SBuf
536 *
537 * Finds the last occurrence of ANY of the characters in the supplied set in
538 * the SBuf.
539 * \return npos if no character in the set could be found
540 * \param endPos if specified, ignore any occurrences after that position
541 * if npos, the entire SBuf is searched
542 */
543 size_type findLastOf(const CharacterSet &set, size_type endPos = npos) const;
544
545 /** Find first occurrence character NOT in character set
546 *
547 * \return npos if all characters in the SBuf are from set
548 * \param startPos if specified, ignore any occurrences before that position
549 * if npos, then npos is always returned
550 *
551 * TODO: rename to camelCase
552 */
553 size_type findFirstNotOf(const CharacterSet &set, size_type startPos = 0) const;
554
555 /** Find last occurrence character NOT in character set
556 *
557 * \return npos if all characters in the SBuf are from set
558 * \param endPos if specified, ignore any occurrences after that position
559 * if npos, then the entire SBuf is searched
560 */
561 size_type findLastNotOf(const CharacterSet &set, size_type endPos = npos) const;
562
563 /// converts all characters to lower case; \see man tolower(3)
564 void toLower();
565
566 /// converts all characters to upper case; \see man toupper(3)
567 void toUpper();
568
569 /// std::string export function
570 std::string toStdString() const { return std::string(buf(),length()); }
571
572 const_iterator begin() const {
573 return const_iterator(*this, 0);
574 }
575
576 const_iterator end() const {
577 return const_iterator(*this, length());
578 }
579
580 const_reverse_iterator rbegin() const {
581 return const_reverse_iterator(*this, length());
582 }
583
584 const_reverse_iterator rend() const {
585 return const_reverse_iterator(*this, 0);
586 }
587
588 // TODO: possibly implement erase() similar to std::string's erase
589 // TODO: possibly implement a replace() call
590
591 /// SBuf object identifier meant for test cases and debugging.
592 /// Does not change when object does, including during assignment.
593 const InstanceId<SBuf> id;
594
595 private:
596
597 /**
598 * Keeps SBuf's MemBlob alive in a blob-destroying context where
599 * a seemingly unrelated memory pointer may belong to the same blob.
600 * For [an extreme] example, consider: a.append(a).
601 * Compared to an SBuf temporary, this class is optimized to
602 * preserve blobs only if needed and to reduce debugging noise.
603 */
604 class Locker
605 {
606 public:
607 Locker(SBuf *parent, const char *otherBuffer) {
608 // lock if otherBuffer intersects the parents buffer area
609 const MemBlob *blob = parent->store_.getRaw();
610 if (blob->mem <= otherBuffer && otherBuffer < (blob->mem + blob->capacity))
611 locket = blob;
612 }
613 private:
614 MemBlob::Pointer locket;
615 };
616 friend class Locker;
617
618 MemBlob::Pointer store_; ///< memory block, possibly shared with other SBufs
619 size_type off_ = 0; ///< our content start offset from the beginning of shared store_
620 size_type len_ = 0; ///< number of our content bytes in shared store_
621 static SBufStats stats; ///< class-wide statistics
622
623 /** obtain prototype store
624 *
625 * Just-created SBufs all share to the same MemBlob.
626 * This call instantiates and returns it.
627 */
628 static MemBlob::Pointer GetStorePrototype();
629
630 /**
631 * obtains a char* to the beginning of this SBuf in memory.
632 * \note the obtained string is NOT null-terminated.
633 */
634 char * buf() const {return (store_->mem+off_);}
635
636 /** returns the pointer to the first char after this SBuf end
637 *
638 * No checks are made that the space returned is safe, checking that is
639 * up to the caller.
640 */
641 char * bufEnd() const {return (store_->mem+off_+len_);}
642
643 /**
644 * Try to guesstimate how big a MemBlob to allocate.
645 * The result is guarranteed to be to be at least the desired size.
646 */
647 size_type estimateCapacity(size_type desired) const {return (2*desired);}
648
649 void reAlloc(size_type newsize);
650
651 void cow(size_type minsize = npos);
652
653 void checkAccessBounds(const size_type pos) const { Must(pos < length()); }
654
655 /** Exports a writable pointer to the SBuf internal storage.
656 * \warning Use with EXTREME caution, this is a dangerous operation.
657 *
658 * Returns a pointer to the first unused byte in the SBuf's storage,
659 * which can be be used for appending. At least minSize bytes will
660 * be available for writing.
661 * The returned pointer must not be stored by the caller, as it will
662 * be invalidated by the first call to a non-const method call
663 * on the SBuf.
664 * This call guarantees to never return nullptr.
665 * \see reserveSpace
666 * \note Unlike reserveSpace(), this method does not guarantee exclusive
667 * buffer ownership. It is instead optimized for a one writer
668 * (appender), many readers scenario by avoiding unnecessary
669 * copying and allocations.
670 * \throw std::exception if the user tries to allocate a too big SBuf
671 */
672 char *rawSpace(size_type minSize);
673
674 /** Low-level append operation
675 *
676 * Takes as input a contiguous area of memory and appends its contents
677 * to the SBuf, taking care of memory management. Does no bounds checking
678 * on the supplied memory buffer, it is the duty of the caller to ensure
679 * that the supplied area is valid.
680 */
681 SBuf& lowAppend(const char * memArea, size_type areaSize);
682 };
683
684 /// Named SBuf::reserve() parameters. Defaults ask for and restrict nothing.
685 class SBufReservationRequirements
686 {
687 public:
688 typedef SBuf::size_type size_type;
689
690 /*
691 * Parameters are listed in the reverse order of importance: Satisfaction of
692 * the lower-listed requirements may violate the higher-listed requirements.
693 * For example, idealSpace has no effect unless it exceeds minSpace.
694 */
695 size_type idealSpace = 0; ///< if allocating anyway, provide this much space
696 size_type minSpace = 0; ///< allocate [at least this much] if spaceSize() is smaller
697 size_type maxCapacity = SBuf::maxSize; ///< do not allocate more than this
698 bool allowShared = true; ///< whether sharing our storage with others is OK
699 };
700
701 /// ostream output operator
702 inline std::ostream &
703 operator <<(std::ostream& os, const SBuf& S)
704 {
705 return S.print(os);
706 }
707
708 /// Returns a lower-cased copy of its parameter.
709 inline SBuf
710 ToUpper(SBuf buf)
711 {
712 buf.toUpper();
713 return buf;
714 }
715
716 /// Returns an upper-cased copy of its parameter.
717 inline SBuf
718 ToLower(SBuf buf)
719 {
720 buf.toLower();
721 return buf;
722 }
723
724 /**
725 * Copy an SBuf into a C-string.
726 *
727 * Guarantees that the output is a c-string of length
728 * no more than SBuf::length()+1 by appending a \0 byte
729 * to the C-string copy of the SBuf contents.
730 *
731 * \note The destination c-string memory MUST be of at least
732 * length()+1 bytes.
733 *
734 * No protection is added to prevent \0 bytes within the string.
735 * Unexpectedly short strings are a problem for the receiver
736 * to deal with if it cares.
737 *
738 * Unlike SBuf::c_str() does not alter the SBuf in any way.
739 */
740 inline void
741 SBufToCstring(char *d, const SBuf &s)
742 {
743 s.copy(d, s.length());
744 d[s.length()] = '\0'; // 0-terminate the destination
745 debugs(1, DBG_DATA, "built c-string '" << d << "' from " << s);
746 }
747
748 /**
749 * Copy an SBuf into a C-string.
750 *
751 * \see SBufToCstring(char *d, const SBuf &s)
752 *
753 * \returns A dynamically allocated c-string based on SBuf.
754 * Use xfree() / safe_free() to release the c-string.
755 */
756 inline char *
757 SBufToCstring(const SBuf &s)
758 {
759 char *d = static_cast<char*>(xmalloc(s.length()+1));
760 SBufToCstring(d, s);
761 return d;
762 }
763
764 inline
765 SBufIterator::SBufIterator(const SBuf &s, size_type pos)
766 : iter(s.rawContent()+pos)
767 {}
768
769 inline bool
770 SBufIterator::operator==(const SBufIterator &s) const
771 {
772 // note: maybe the sbuf comparison is unnecessary?
773 return iter == s.iter;
774 }
775
776 inline bool
777 SBufIterator::operator!=(const SBufIterator &s) const
778 {
779 // note: maybe the sbuf comparison is unnecessary?
780 return iter != s.iter;
781 }
782
783 #endif /* SQUID_SBUF_H */
784