2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 24 SBuf */
11 #ifndef SQUID_SRC_SBUF_SBUF_H
12 #define SQUID_SRC_SBUF_SBUF_H
14 #include "base/InstanceId.h"
15 #include "base/TextException.h"
16 #include "debug/Stream.h"
18 #include "sbuf/forward.h"
19 #include "sbuf/MemBlob.h"
20 #include "sbuf/Stats.h"
29 /* SBuf placeholder for printf */
31 #define SQUIDSBUFPH "%.*s"
32 #define SQUIDSBUFPRINT(s) (s).plength(),(s).rawContent()
33 #endif /* SQUIDSBUFPH */
35 // TODO: move within SBuf and rename
43 /** Forward input const_iterator for SBufs
45 * Please note that any operation on the underlying SBuf may invalidate
46 * all iterators over it, resulting in undefined behavior by them.
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&;
59 typedef MemBlob::size_type size_type
;
60 bool operator==(const SBufIterator
&s
) const;
61 bool operator!=(const SBufIterator
&s
) const;
63 const char &operator*() const { return *iter
; }
64 SBufIterator
& operator++() { ++iter
; return *this; }
67 SBufIterator(const SBuf
&, size_type
);
69 const char *iter
= nullptr;
72 /** Reverse input const_iterator for SBufs
74 * Please note that any operation on the underlying SBuf may invalidate
75 * all iterators over it, resulting in undefined behavior by them.
77 class SBufReverseIterator
: public SBufIterator
81 SBufReverseIterator
& operator++() { --iter
; return *this;}
82 const char &operator*() const { return *(iter
-1); }
84 SBufReverseIterator(const SBuf
&s
, size_type sz
) : SBufIterator(s
,sz
) {}
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.
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)
102 /// Maximum size of a SBuf. By design it MUST be < MAX(size_type)/2. Currently 256Mb.
103 static const size_type maxSize
= 0xfffffff;
105 /// create an empty (zero-size) SBuf
108 SBuf(SBuf
&& S
) : store_(std::move(S
.store_
)), off_(S
.off_
), len_(S
.len_
) {
110 S
.store_
= nullptr; //RefCount supports nullptr, and S is about to be destructed
114 /** Constructor: import c-style string
116 * Create a new SBuf containing a COPY of the contents of the
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
124 explicit SBuf(const char *S
, size_type n
);
125 explicit SBuf(const char *S
);
127 /// Constructor: import std::string. Contents are copied.
128 explicit SBuf(const std::string
&s
);
132 /** Explicit assignment.
134 * Current SBuf will share backing store with the assigned one.
136 SBuf
& assign(const SBuf
&S
);
138 /** Assignment operator.
140 * Current SBuf will share backing store with the assigned one.
142 SBuf
& operator =(const SBuf
& S
) {return assign(S
);}
143 SBuf
& operator =(SBuf
&&S
) {
146 store_
= std::move(S
.store_
);
149 S
.store_
= nullptr; //RefCount supports NULL, and S is about to be destructed
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.
160 /** Import a c-string into a SBuf, copying the data.
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())
170 SBuf
& assign(const char *S
, size_type n
);
171 SBuf
& assign(const char *S
) {return assign(S
,npos
);}
173 /** Assignment operator. Copy a NULL-terminated c-style string into a SBuf.
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.
179 SBuf
& operator =(const char *S
) {return assign(S
);}
181 /** reset the SBuf as if it was just created.
183 * Resets the SBuf to empty, memory is freed lazily.
189 * Append the supplied SBuf to the current one; extend storage as needed.
191 SBuf
& append(const SBuf
& S
);
193 /// \copydoc push_back(char)
194 SBuf
& append(const char c
) { push_back(c
); return *this; }
196 /// Append a single character. The character may be NUL (\0).
197 void push_back(char);
199 /** Append operation for C-style strings.
201 * Append the supplied c-string to the SBuf; extend storage
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,
208 * \note to append a std::string use the pattern
209 * cstr_append(stdstr.data(), stdstd.length())
211 SBuf
& append(const char * S
, size_type Ssize
);
212 SBuf
& append(const char * S
) { return append(S
,npos
); }
214 /** Assignment operation with printf(3)-style definition
215 * \note arguments may be evaluated more than once, be careful
218 SBuf
& Printf(const char *fmt
, ...) PRINTF_FORMAT_ARG2
;
220 /** Append operation with printf-style arguments
221 * \note arguments may be evaluated more than once, be careful
224 SBuf
& appendf(const char *fmt
, ...) PRINTF_FORMAT_ARG2
;
226 /** Append operation, with vsprintf(3)-style arguments.
227 * \note arguments may be evaluated more than once, be careful
230 SBuf
& vappendf(const char *fmt
, va_list vargs
);
232 /// print the SBuf contents to the supplied ostream
233 std::ostream
& print(std::ostream
&os
) const;
235 /** print SBuf contents and debug information about the SBuf to an ostream
237 * Debug function, dumps to a stream information on the current SBuf,
238 * including low-level details and statistics.
240 std::ostream
& dump(std::ostream
&os
) const;
242 /** random-access read to any char within the SBuf
244 * does not check access bounds. If you need that, use at()
246 char operator [](size_type pos
) const {++stats
.getChar
; return store_
->mem
[off_
+pos
];}
248 /** random-access read to any char within the SBuf.
250 * \throw std::exception when access is out of bounds
251 * \note bounds is 0 <= pos < length(); caller must pay attention to signedness
253 char at(size_type pos
) const {checkAccessBounds(pos
); return operator[](pos
);}
255 /** direct-access set a byte at a specified operation.
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.
263 void setAt(size_type pos
, char toset
);
265 /** compare to other SBuf, str(case)cmp-style
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
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
);
278 /// shorthand version for compare()
279 inline int cmp(const SBuf
&S
, const size_type n
) const {
280 return compare(S
,caseSensitive
,n
);
282 inline int cmp(const SBuf
&S
) const {
283 return compare(S
,caseSensitive
,npos
);
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
);
290 inline int caseCmp(const SBuf
&S
) const {
291 return compare(S
,caseInsensitive
,npos
);
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
);
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
);
304 inline int cmp(const char *S
) const {
305 return compare(S
,caseSensitive
,npos
);
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
);
312 inline int caseCmp(const char *S
) const {
313 return compare(S
,caseInsensitive
,npos
);
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
321 bool startsWith(const SBuf
&S
, const SBufCaseSensitive isCaseSensitive
= caseSensitive
) const;
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);}
330 /** Consume bytes at the head of the SBuf
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.
339 SBuf
consume(size_type n
= npos
);
341 /// gets global statistic information
342 static const SBufStats
& GetStats();
344 /** Copy SBuf contents into user-supplied C buffer.
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.
350 size_type
copy(char *dest
, size_type n
) const;
352 /** exports a pointer to the SBuf internal storage.
353 * \warning ACCESSING RAW STORAGE IS DANGEROUS!
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.
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
370 * SBuf foo("some string");
371 * const char *bar = foo.rawContent();
372 * doSomething(bar); //safe
373 * foo.append(" other string");
374 * doSomething(bar); //unsafe
377 const char* rawContent() const;
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
);
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
);
392 /** Obtain how much free space is available in the backing store.
394 * \note: unless the client just cow()ed, it is not guaranteed that
395 * the free space can be used.
397 size_type
spaceSize() const { return store_
->spaceSize(); }
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
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.
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
418 /// Returns the number of bytes stored in SBuf.
419 size_type
length() const {return len_
;}
421 /** Get the length of the SBuf, as a signed integer
423 * Compatibility function for printf(3) which requires a signed int
424 * \throw std::exception if buffer length does not fit a signed integer
426 int plength() const {
427 Must(length() <= INT_MAX
);
428 return static_cast<int>(length());
431 /** Check whether the SBuf is empty
433 * \return true if length() == 0
435 bool isEmpty() const {return (len_
==0);}
437 /** Request to guarantee the SBuf's free store space.
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
444 void reserveSpace(size_type minSpace
) {
445 Must(minSpace
<= maxSize
);
446 Must(length() <= maxSize
- minSpace
);
447 reserveCapacity(length()+minSpace
);
450 /** Request to guarantee the SBuf's store capacity
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
458 void reserveCapacity(size_type minCapacity
);
460 /** Accommodate caller's requirements regarding SBuf's storage if possible.
462 * \return spaceSize(), which may be zero
464 size_type
reserve(const SBufReservationRequirements
&requirements
);
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
480 SBuf
& chop(size_type pos
, size_type n
= npos
);
482 /** Remove characters in the toremove set at the beginning, end or both
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
489 SBuf
& trim(const SBuf
&toRemove
, bool atBeginning
= true, bool atEnd
= true);
491 /** Extract a part of the current SBuf.
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.
497 SBuf
substr(size_type pos
, size_type n
= npos
) const;
499 /** Find first occurrence of character in SBuf
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
507 size_type
find(char c
, size_type startPos
= 0) const;
509 /** Find first occurrence of SBuf in SBuf.
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
517 size_type
find(const SBuf
& str
, size_type startPos
= 0) const;
519 /** Find last occurrence of character in SBuf
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
526 size_type
rfind(char c
, size_type endPos
= npos
) const;
528 /** Find last occurrence of SBuf in SBuf
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
536 size_type
rfind(const SBuf
&str
, size_type endPos
= npos
) const;
538 /** Find first occurrence of character of set in SBuf
540 * Finds the first occurrence of ANY of the characters in the supplied set in
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
546 * TODO: rename to camelCase
548 size_type
findFirstOf(const CharacterSet
&set
, size_type startPos
= 0) const;
550 /** Find last occurrence of character of set in SBuf
552 * Finds the last occurrence of ANY of the characters in the supplied set in
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
558 size_type
findLastOf(const CharacterSet
&set
, size_type endPos
= npos
) const;
560 /** Find first occurrence character NOT in character set
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
566 * TODO: rename to camelCase
568 size_type
findFirstNotOf(const CharacterSet
&set
, size_type startPos
= 0) const;
570 /** Find last occurrence character NOT in character set
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
576 size_type
findLastNotOf(const CharacterSet
&set
, size_type endPos
= npos
) const;
578 /// converts all characters to lower case; \see man tolower(3)
581 /// converts all characters to upper case; \see man toupper(3)
584 /// std::string export function
585 std::string
toStdString() const { return std::string(buf(),length()); }
587 const_iterator
begin() const {
588 return const_iterator(*this, 0);
591 const_iterator
end() const {
592 return const_iterator(*this, length());
595 const_reverse_iterator
rbegin() const {
596 return const_reverse_iterator(*this, length());
599 const_reverse_iterator
rend() const {
600 return const_reverse_iterator(*this, 0);
603 // TODO: possibly implement erase() similar to std::string's erase
604 // TODO: possibly implement a replace() call
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
;
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.
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
))
629 MemBlob::Pointer locket
;
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
638 /** obtain prototype store
640 * Just-created SBufs all share to the same MemBlob.
641 * This call instantiates and returns it.
643 static MemBlob::Pointer
GetStorePrototype();
646 * obtains a char* to the beginning of this SBuf in memory.
647 * \note the obtained string is NOT null-terminated.
649 char * buf() const {return (store_
->mem
+off_
);}
651 /** returns the pointer to the first char after this SBuf end
653 * No checks are made that the space returned is safe, checking that is
656 char * bufEnd() const {return (store_
->mem
+off_
+len_
);}
659 * Try to guesstimate how big a MemBlob to allocate.
660 * The result is guaranteed to be to be at least the desired size.
662 size_type
estimateCapacity(size_type desired
) const {return (2*desired
);}
664 void reAlloc(size_type newsize
);
666 void cow(size_type minsize
= npos
);
668 void checkAccessBounds(const size_type pos
) const { Must(pos
< length()); }
670 /** Exports a writable pointer to the SBuf internal storage.
671 * \warning Use with EXTREME caution, this is a dangerous operation.
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
679 * This call guarantees to never return nullptr.
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
687 char *rawSpace(size_type minSize
);
689 /** Low-level append operation
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.
696 SBuf
& lowAppend(const char * memArea
, size_type areaSize
);
699 /// Named SBuf::reserve() parameters. Defaults ask for and restrict nothing.
700 class SBufReservationRequirements
703 typedef SBuf::size_type size_type
;
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.
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
716 /// ostream output operator
717 inline std::ostream
&
718 operator <<(std::ostream
& os
, const SBuf
& S
)
723 /// Returns a lower-cased copy of its parameter.
731 /// Returns an upper-cased copy of its parameter.
740 * Copy an SBuf into a C-string.
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.
746 * \note The destination c-string memory MUST be of at least
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.
753 * Unlike SBuf::c_str() does not alter the SBuf in any way.
756 SBufToCstring(char *d
, const SBuf
&s
)
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
);
764 * Copy an SBuf into a C-string.
766 * \see SBufToCstring(char *d, const SBuf &s)
768 * \returns A dynamically allocated c-string based on SBuf.
769 * Use xfree() / safe_free() to release the c-string.
772 SBufToCstring(const SBuf
&s
)
774 char *d
= static_cast<char*>(xmalloc(s
.length()+1));
780 SBufIterator::SBufIterator(const SBuf
&s
, size_type pos
)
781 : iter(s
.rawContent()+pos
)
785 SBufIterator::operator==(const SBufIterator
&s
) const
787 // note: maybe the sbuf comparison is unnecessary?
788 return iter
== s
.iter
;
792 SBufIterator::operator!=(const SBufIterator
&s
) const
794 // note: maybe the sbuf comparison is unnecessary?
795 return iter
!= s
.iter
;
798 #endif /* SQUID_SRC_SBUF_SBUF_H */