]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 1996-2025 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 |