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