SBuf.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2018 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 #include "squid.h"
10 #include "base/CharacterSet.h"
11 #include "base/RefCount.h"
12 #include "Debug.h"
13 #include "sbuf/DetailedStats.h"
14 #include "sbuf/SBuf.h"
15 #include "util.h"
16 
17 #include <cstring>
18 #include <functional>
19 #include <iostream>
20 #include <sstream>
21 
22 #ifdef VA_COPY
23 #undef VA_COPY
24 #endif
25 #if defined HAVE_VA_COPY
26 #define VA_COPY va_copy
27 #elif defined HAVE___VA_COPY
28 #define VA_COPY __va_copy
29 #endif
30 
32 
36 
37 SBuf::SBuf() : store_(GetStorePrototype())
38 {
39  debugs(24, 8, id << " created");
40  ++stats.alloc;
41  ++stats.live;
42 }
43 
44 SBuf::SBuf(const SBuf &S)
45  : store_(S.store_), off_(S.off_), len_(S.len_)
46 {
47  debugs(24, 8, id << " created from id " << S.id);
48  ++stats.alloc;
49  ++stats.allocCopy;
50  ++stats.live;
51 }
52 
53 SBuf::SBuf(const std::string &s) : store_(GetStorePrototype())
54 {
55  debugs(24, 8, id << " created from std::string");
56  lowAppend(s.data(),s.length());
57  ++stats.alloc;
58  ++stats.live;
59 }
60 
61 SBuf::SBuf(const char *S, size_type n) : store_(GetStorePrototype())
62 {
63  append(S,n);
64  ++stats.alloc;
66  ++stats.live;
67 }
68 
69 SBuf::SBuf(const char *S) : store_(GetStorePrototype())
70 {
71  append(S,npos);
72  ++stats.alloc;
74  ++stats.live;
75 }
76 
78 {
79  debugs(24, 8, id << " destructed");
80  --stats.live;
82 }
83 
86 {
87  static MemBlob::Pointer InitialStore = new MemBlob(0);
88  return InitialStore;
89 }
90 
91 SBuf&
92 SBuf::assign(const SBuf &S)
93 {
94  debugs(24, 7, "assigning " << id << " from " << S.id);
95  if (&S == this) //assignment to self. Noop.
96  return *this;
97  ++stats.assignFast;
98  store_ = S.store_;
99  off_ = S.off_;
100  len_ = S.len_;
101  return *this;
102 }
103 
104 SBuf&
105 SBuf::assign(const char *S, size_type n)
106 {
107  const Locker blobKeeper(this, S);
108  debugs(24, 6, id << " from c-string, n=" << n << ")");
109  clear();
110  return append(S, n); //bounds checked in append()
111 }
112 
113 void
115 {
116  Must(minCapacity <= maxSize);
117  cow(minCapacity);
118 }
119 
122 {
123  debugs(24, 8, id << " was: " << off_ << '+' << len_ << '+' << spaceSize() <<
124  '=' << store_->capacity);
125 
126  const bool mustRealloc = !req.allowShared && store_->LockCount() > 1;
127 
128  if (!mustRealloc && spaceSize() >= req.minSpace)
129  return spaceSize(); // the caller is content with what we have
130 
131  /* only reallocation can make the caller happy */
132 
133  if (!mustRealloc && len_ >= req.maxCapacity)
134  return spaceSize(); // but we cannot reallocate
135 
136  const size_type desiredSpace = std::max(req.minSpace, req.idealSpace);
137  const size_type newSpace = std::min(desiredSpace, maxSize - len_);
138  reserveCapacity(std::min(len_ + newSpace, req.maxCapacity));
139  debugs(24, 7, id << " now: " << off_ << '+' << len_ << '+' << spaceSize() <<
140  '=' << store_->capacity);
141  return spaceSize(); // reallocated and probably reserved enough space
142 }
143 
144 char *
146 {
147  char *space = rawSpace(anticipatedSize);
148  debugs(24, 8, id << " start appending up to " << anticipatedSize << " bytes");
149  return space;
150 }
151 
152 void
153 SBuf::rawAppendFinish(const char *start, size_type actualSize)
154 {
155  Must(bufEnd() == start);
156  Must(store_->canAppend(off_ + len_, actualSize));
157  debugs(24, 8, id << " finish appending " << actualSize << " bytes");
158 
159  size_type newSize = length() + actualSize;
160  Must2(newSize <= min(maxSize,store_->capacity-off_), "raw append overflow");
161  len_ = newSize;
162  store_->size = off_ + newSize;
163 }
164 
165 char *
167 {
168  Must(length() <= maxSize - minSpace);
169  debugs(24, 7, "reserving " << minSpace << " for " << id);
170  ++stats.rawAccess;
171  // we're not concerned about RefCounts here,
172  // the store knows the last-used portion. If
173  // it's available, we're effectively claiming ownership
174  // of it. If it's not, we need to go away (realloc)
175  if (store_->canAppend(off_+len_, minSpace)) {
176  debugs(24, 7, id << " not growing");
177  return bufEnd();
178  }
179  // TODO: we may try to memmove before realloc'ing in order to avoid
180  // one allocation operation, if we're the sole owners of a MemBlob.
181  // Maybe some heuristic on off_ and length()?
182  cow(minSpace+length());
183  return bufEnd();
184 }
185 
186 void
188 {
189 #if 0
190  //enabling this code path, the store will be freed and reinitialized
191  store_ = GetStorePrototype(); //uncomment to actually free storage upon clear()
192 #else
193  //enabling this code path, we try to release the store without deallocating it.
194  // will be lazily reallocated if needed.
195  if (store_->LockCount() == 1)
196  store_->clear();
197 #endif
198  len_ = 0;
199  off_ = 0;
200  ++stats.clear;
201 }
202 
203 SBuf&
205 {
206  if (isEmpty() && store_ == GetStorePrototype())
207  return (*this = S); // optimization: avoid needless copying
208 
209  const Locker blobKeeper(this, S.buf());
210  return lowAppend(S.buf(), S.length());
211 }
212 
213 SBuf &
214 SBuf::append(const char * S, size_type Ssize)
215 {
216  const Locker blobKeeper(this, S);
217  if (S == NULL)
218  return *this;
219  if (Ssize == SBuf::npos)
220  Ssize = strlen(S);
221  debugs(24, 7, "from c-string to id " << id);
222  // coverity[access_dbuff_in_call]
223  return lowAppend(S, Ssize);
224 }
225 
226 SBuf &
227 SBuf::append(const char c)
228 {
229  return lowAppend(&c, 1);
230 }
231 
232 SBuf&
233 SBuf::Printf(const char *fmt, ...)
234 {
235  // with printf() the fmt or an arg might be a dangerous char*
236  // NP: cant rely on vappendf() Locker because of clear()
237  const Locker blobKeeper(this, buf());
238 
239  va_list args;
240  va_start(args, fmt);
241  clear();
242  vappendf(fmt, args);
243  va_end(args);
244  return *this;
245 }
246 
247 SBuf&
248 SBuf::appendf(const char *fmt, ...)
249 {
250  va_list args;
251  va_start(args, fmt);
252  vappendf(fmt, args);
253  va_end(args);
254  return *this;
255 }
256 
257 SBuf&
258 SBuf::vappendf(const char *fmt, va_list vargs)
259 {
260  // with (v)appendf() the fmt or an arg might be a dangerous char*
261  const Locker blobKeeper(this, buf());
262 
263  Must(fmt != NULL);
264  int sz = 0;
265  //reserve twice the format-string size, it's a likely heuristic
266  size_type requiredSpaceEstimate = strlen(fmt)*2;
267 
268  char *space = rawSpace(requiredSpaceEstimate);
269 #ifdef VA_COPY
270  va_list ap;
271  VA_COPY(ap, vargs);
272  sz = vsnprintf(space, spaceSize(), fmt, ap);
273  va_end(ap);
274 #else
275  sz = vsnprintf(space, spaceSize(), fmt, vargs);
276 #endif
277  Must2(sz >= 0, "vsnprintf() output error");
278 
279  /* check for possible overflow */
280  /* snprintf on Linux returns -1 on output errors, or the size
281  * that would have been written if enough space had been available */
282  /* vsnprintf is standard in C99 */
283 
284  if (sz >= static_cast<int>(spaceSize())) {
285  // not enough space on the first go, we now know how much we need
286  requiredSpaceEstimate = sz*2; // TODO: tune heuristics
287  space = rawSpace(requiredSpaceEstimate);
288  sz = vsnprintf(space, spaceSize(), fmt, vargs);
289  Must2(sz >= 0, "vsnprintf() output error despite increased buffer space");
290  }
291 
292  // data was appended, update internal state
293  len_ += sz;
294 
295  /* C99 specifies that the final '\0' is not counted in vsnprintf's
296  * return value. Older compilers/libraries might instead count it */
297  /* check whether '\0' was appended and counted */
298  static bool snPrintfTerminatorChecked = false;
299  static bool snPrintfTerminatorCounted = false;
300  if (!snPrintfTerminatorChecked) {
301  char testbuf[16];
302  snPrintfTerminatorCounted = snprintf(testbuf, sizeof(testbuf),
303  "%s", "1") == 2;
304  snPrintfTerminatorChecked = true;
305  }
306  if (snPrintfTerminatorCounted) {
307  --sz;
308  --len_;
309  }
310 
311  store_->size += sz;
312  ++stats.append;
313 
314  return *this;
315 }
316 
317 std::ostream&
318 SBuf::print(std::ostream &os) const
319 {
320  os.write(buf(), length());
321  ++stats.toStream;
322  return os;
323 }
324 
325 std::ostream&
326 SBuf::dump(std::ostream &os) const
327 {
328  os << id
329  << ": ";
330  store_->dump(os);
331  os << ", offset:" << off_
332  << ", len:" << len_
333  << ") : '";
334  print(os);
335  os << '\'' << std::endl;
336  return os;
337 # if 0
338  // alternate implementation, based on Raw() API.
339  os << Raw("SBuf", buf(), length()) <<
340  ". id: " << id <<
341  ", offset:" << off_ <<
342  ", len:" << len_ <<
343  ", store: ";
344  store_->dump(os);
345  os << std::endl;
346  return os;
347 #endif
348 }
349 
350 void
351 SBuf::setAt(size_type pos, char toset)
352 {
353  checkAccessBounds(pos);
354  cow();
355  store_->mem[off_+pos] = toset;
356  ++stats.setChar;
357 }
358 
359 static int
360 memcasecmp(const char *b1, const char *b2, SBuf::size_type len)
361 {
362  int rv=0;
363  while (len > 0) {
364  rv = tolower(*b1)-tolower(*b2);
365  if (rv != 0)
366  return rv;
367  ++b1;
368  ++b2;
369  --len;
370  }
371  return rv;
372 }
373 
374 int
375 SBuf::compare(const SBuf &S, const SBufCaseSensitive isCaseSensitive, const size_type n) const
376 {
377  if (n != npos) {
378  debugs(24, 8, "length specified. substr and recurse");
379  return substr(0,n).compare(S.substr(0,n),isCaseSensitive);
380  }
381 
382  const size_type byteCompareLen = min(S.length(), length());
383  ++stats.compareSlow;
384  int rv = 0;
385  debugs(24, 8, "comparing length " << byteCompareLen);
386  if (isCaseSensitive == caseSensitive) {
387  rv = memcmp(buf(), S.buf(), byteCompareLen);
388  } else {
389  rv = memcasecmp(buf(), S.buf(), byteCompareLen);
390  }
391  if (rv != 0) {
392  debugs(24, 8, "result: " << rv);
393  return rv;
394  }
395  if (n <= length() || n <= S.length()) {
396  debugs(24, 8, "same contents and bounded length. Equal");
397  return 0;
398  }
399  if (length() == S.length()) {
400  debugs(24, 8, "same contents and same length. Equal");
401  return 0;
402  }
403  if (length() > S.length()) {
404  debugs(24, 8, "lhs is longer than rhs. Result is 1");
405  return 1;
406  }
407  debugs(24, 8, "rhs is longer than lhs. Result is -1");
408  return -1;
409 }
410 
411 int
412 SBuf::compare(const char *s, const SBufCaseSensitive isCaseSensitive, const size_type n) const
413 {
414  // 0-length comparison is always true regardless of buffer states
415  if (!n) {
416  ++stats.compareFast;
417  return 0;
418  }
419 
420  // N-length compare MUST provide a non-NULL C-string pointer
421  assert(s);
422 
423  // when this is a 0-length string, no need for any complexity.
424  if (!length()) {
425  ++stats.compareFast;
426  return '\0' - *s;
427  }
428 
429  // brute-force scan in order to avoid ever needing strlen() on a c-string.
430  ++stats.compareSlow;
431  const char *left = buf();
432  const char *right = s;
433  int rv = 0;
434  // what area to scan.
435  // n may be npos, but we treat that as a huge positive value
436  size_type byteCount = min(length(), n);
437 
438  // loop until we find a difference, a '\0', or reach the end of area to scan
439  if (isCaseSensitive == caseSensitive) {
440  while ((rv = *left - *right++) == 0) {
441  if (*left++ == '\0' || --byteCount == 0)
442  break;
443  }
444  } else {
445  while ((rv = tolower(*left) - tolower(*right++)) == 0) {
446  if (*left++ == '\0' || --byteCount == 0)
447  break;
448  }
449  }
450 
451  // If we stopped scanning because we reached the end
452  // of buf() before we reached the end of s,
453  // pretend we have a 0-terminator there to compare.
454  // NP: the loop already incremented "right" ready for this comparison
455  if (!byteCount && length() < n)
456  return '\0' - *right;
457 
458  // If we found a difference within the scan area,
459  // or we found a '\0',
460  // or all n characters were identical (and none was \0).
461  return rv;
462 }
463 
464 bool
465 SBuf::startsWith(const SBuf &S, const SBufCaseSensitive isCaseSensitive) const
466 {
467  debugs(24, 8, id << " startsWith " << S.id << ", caseSensitive: " <<
468  isCaseSensitive);
469  if (length() < S.length()) {
470  debugs(24, 8, "no, too short");
471  ++stats.compareFast;
472  return false;
473  }
474  return (compare(S, isCaseSensitive, S.length()) == 0);
475 }
476 
477 bool
478 SBuf::operator ==(const SBuf & S) const
479 {
480  debugs(24, 8, id << " == " << S.id);
481  if (length() != S.length()) {
482  debugs(24, 8, "no, different lengths");
483  ++stats.compareFast;
484  return false; //shortcut: must be equal length
485  }
486  if (store_ == S.store_ && off_ == S.off_) {
487  debugs(24, 8, "yes, same length and backing store");
488  ++stats.compareFast;
489  return true; //shortcut: same store, offset and length
490  }
491  ++stats.compareSlow;
492  const bool rv = (0 == memcmp(buf(), S.buf(), length()));
493  debugs(24, 8, "returning " << rv);
494  return rv;
495 }
496 
497 bool
498 SBuf::operator !=(const SBuf & S) const
499 {
500  return !(*this == S);
501 }
502 
503 SBuf
505 {
506  if (n == npos)
507  n = length();
508  else
509  n = min(n, length());
510  debugs(24, 8, id << " consume " << n);
511  SBuf rv(substr(0, n));
512  chop(n);
513  return rv;
514 }
515 
516 const
518 {
519  return stats;
520 }
521 
523 SBuf::copy(char *dest, size_type n) const
524 {
525  size_type toexport = min(n,length());
526  memcpy(dest, buf(), toexport);
527  ++stats.copyOut;
528  return toexport;
529 }
530 
531 const char*
533 {
534  ++stats.rawAccess;
535  return buf();
536 }
537 
538 const char*
540 {
541  ++stats.rawAccess;
542  /* null-terminate the current buffer, by hand-appending a \0 at its tail but
543  * without increasing its length. May COW, the side-effect is to guarantee that
544  * the MemBlob's tail is availabe for us to use */
545  *rawSpace(1) = '\0';
546  ++store_->size;
547  ++stats.setChar;
549  return buf();
550 }
551 
552 SBuf&
554 {
555  if (pos == npos || pos > length())
556  pos = length();
557 
558  if (n == npos || (pos+n) > length())
559  n = length() - pos;
560 
561  // if there will be nothing left, reset the buffer while we can
562  if (pos == length() || n == 0) {
563  clear();
564  return *this;
565  }
566 
567  ++stats.chop;
568  off_ += pos;
569  len_ = n;
570  return *this;
571 }
572 
573 SBuf&
574 SBuf::trim(const SBuf &toRemove, bool atBeginning, bool atEnd)
575 {
576  ++stats.trim;
577  if (atEnd) {
578  const char *p = bufEnd()-1;
579  while (!isEmpty() && memchr(toRemove.buf(), *p, toRemove.length()) != NULL) {
580  //current end-of-buf is in the searched set
581  --len_;
582  --p;
583  }
584  }
585  if (atBeginning) {
586  const char *p = buf();
587  while (!isEmpty() && memchr(toRemove.buf(), *p, toRemove.length()) != NULL) {
588  --len_;
589  ++off_;
590  ++p;
591  }
592  }
593  if (isEmpty())
594  clear();
595  return *this;
596 }
597 
598 SBuf
600 {
601  SBuf rv(*this);
602  rv.chop(pos, n); //stats handled by callee
603  return rv;
604 }
605 
607 SBuf::find(char c, size_type startPos) const
608 {
609  ++stats.find;
610 
611  if (startPos == npos) // can't find anything if we look past end of SBuf
612  return npos;
613 
614  // std::string returns npos if needle is outside hay
615  if (startPos > length())
616  return npos;
617 
618  const void *i = memchr(buf()+startPos, (int)c, (size_type)length()-startPos);
619 
620  if (i == NULL)
621  return npos;
622 
623  return (static_cast<const char *>(i)-buf());
624 }
625 
627 SBuf::find(const SBuf &needle, size_type startPos) const
628 {
629  if (startPos == npos) { // can't find anything if we look past end of SBuf
630  ++stats.find;
631  return npos;
632  }
633 
634  // std::string allows needle to overhang hay but not start outside
635  if (startPos > length()) {
636  ++stats.find;
637  return npos;
638  }
639 
640  // for empty needle std::string returns startPos
641  if (needle.length() == 0) {
642  ++stats.find;
643  return startPos;
644  }
645 
646  // if needle length is 1 use the char search
647  if (needle.length() == 1)
648  return find(needle[0], startPos);
649 
650  ++stats.find;
651 
652  char *start = buf()+startPos;
653  char *lastPossible = buf()+length()-needle.length()+1;
654  char needleBegin = needle[0];
655 
656  debugs(24, 7, "looking for " << needle << "starting at " << startPos <<
657  " in id " << id);
658  while (start < lastPossible) {
659  char *tmp;
660  debugs(24, 8, " begin=" << (void *) start <<
661  ", lastPossible=" << (void*) lastPossible );
662  tmp = static_cast<char *>(memchr(start, needleBegin, lastPossible-start));
663  if (tmp == NULL) {
664  debugs(24, 8, "First byte not found");
665  return npos;
666  }
667  // lastPossible guarrantees no out-of-bounds with memcmp()
668  if (0 == memcmp(needle.buf(), tmp, needle.length())) {
669  debugs(24, 8, "Found at " << (tmp-buf()));
670  return (tmp-buf());
671  }
672  start = tmp+1;
673  }
674  debugs(24, 8, "not found");
675  return npos;
676 }
677 
679 SBuf::rfind(const SBuf &needle, SBuf::size_type endPos) const
680 {
681  // when the needle is 1 char, use the 1-char rfind()
682  if (needle.length() == 1)
683  return rfind(needle[0], endPos);
684 
685  ++stats.find;
686 
687  // needle is bigger than haystack, impossible find
688  if (length() < needle.length())
689  return npos;
690 
691  // if startPos is npos, std::string scans from the end of hay
692  if (endPos == npos || endPos > length()-needle.length())
693  endPos = length()-needle.length();
694 
695  // an empty needle found at the end of the haystack
696  if (needle.length() == 0)
697  return endPos;
698 
699  char *bufBegin = buf();
700  char *cur = bufBegin+endPos;
701  const char needleBegin = needle[0];
702  while (cur >= bufBegin) {
703  if (*cur == needleBegin) {
704  if (0 == memcmp(needle.buf(), cur, needle.length())) {
705  // found
706  return (cur-buf());
707  }
708  }
709  --cur;
710  }
711  return npos;
712 }
713 
715 SBuf::rfind(char c, SBuf::size_type endPos) const
716 {
717  ++stats.find;
718 
719  // shortcut: haystack is empty, can't find anything by definition
720  if (length() == 0)
721  return npos;
722 
723  // on npos input std::string compares last octet of hay
724  if (endPos == npos || endPos >= length()) {
725  endPos = length();
726  } else {
727  // NP: off-by-one weirdness:
728  // endPos is an offset ... 0-based
729  // length() is a count ... 1-based
730  // memrhr() requires a 1-based count of space to scan.
731  ++endPos;
732  }
733 
734  if (length() == 0)
735  return endPos;
736 
737  const void *i = memrchr(buf(), (int)c, (size_type)endPos);
738 
739  if (i == NULL)
740  return npos;
741 
742  return (static_cast<const char *>(i)-buf());
743 }
744 
746 SBuf::findFirstOf(const CharacterSet &set, size_type startPos) const
747 {
748  ++stats.find;
749 
750  if (startPos == npos)
751  return npos;
752 
753  if (startPos >= length())
754  return npos;
755 
756  debugs(24, 7, "first of characterset " << set.name << " in id " << id);
757  char *cur = buf()+startPos;
758  const char *bufend = bufEnd();
759  while (cur < bufend) {
760  if (set[*cur])
761  return cur-buf();
762  ++cur;
763  }
764  debugs(24, 7, "not found");
765  return npos;
766 }
767 
769 SBuf::findFirstNotOf(const CharacterSet &set, size_type startPos) const
770 {
771  ++stats.find;
772 
773  if (startPos == npos)
774  return npos;
775 
776  if (startPos >= length())
777  return npos;
778 
779  debugs(24, 7, "first not of characterset " << set.name << " in id " << id);
780  char *cur = buf()+startPos;
781  const char *bufend = bufEnd();
782  while (cur < bufend) {
783  if (!set[*cur])
784  return cur-buf();
785  ++cur;
786  }
787  debugs(24, 7, "not found");
788  return npos;
789 }
790 
792 SBuf::findLastOf(const CharacterSet &set, size_type endPos) const
793 {
794  ++stats.find;
795 
796  if (isEmpty())
797  return npos;
798 
799  if (endPos == npos || endPos >= length())
800  endPos = length() - 1;
801 
802  debugs(24, 7, "last of characterset " << set.name << " in id " << id);
803  const char *start = buf();
804  for (const char *cur = start + endPos; cur >= start; --cur) {
805  if (set[*cur])
806  return cur - start;
807  }
808  debugs(24, 7, "not found");
809  return npos;
810 }
811 
813 SBuf::findLastNotOf(const CharacterSet &set, size_type endPos) const
814 {
815  ++stats.find;
816 
817  if (isEmpty())
818  return npos;
819 
820  if (endPos == npos || endPos >= length())
821  endPos = length() - 1;
822 
823  debugs(24, 7, "last not of characterset " << set.name << " in id " << id);
824  const char *start = buf();
825  for (const char *cur = start + endPos; cur >= start; --cur) {
826  if (!set[*cur])
827  return cur - start;
828  }
829  debugs(24, 7, "not found");
830  return npos;
831 }
832 
833 void
835 {
836  debugs(24, 8, "\"" << *this << "\"");
837  for (size_type j = 0; j < length(); ++j) {
838  const int c = (*this)[j];
839  if (isupper(c))
840  setAt(j, tolower(c));
841  }
842  debugs(24, 8, "result: \"" << *this << "\"");
843  ++stats.caseChange;
844 }
845 
846 void
848 {
849  debugs(24, 8, "\"" << *this << "\"");
850  for (size_type j = 0; j < length(); ++j) {
851  const int c = (*this)[j];
852  if (islower(c))
853  setAt(j, toupper(c));
854  }
855  debugs(24, 8, "result: \"" << *this << "\"");
856  ++stats.caseChange;
857 }
858 
867 void
869 {
870  debugs(24, 8, id << " new size: " << newsize);
871  Must(newsize <= maxSize);
872  MemBlob::Pointer newbuf = new MemBlob(newsize);
873  if (length() > 0)
874  newbuf->append(buf(), length());
875  store_ = newbuf;
876  off_ = 0;
877  ++stats.cowSlow;
878  debugs(24, 7, id << " new store capacity: " << store_->capacity);
879 }
880 
881 SBuf&
882 SBuf::lowAppend(const char * memArea, size_type areaSize)
883 {
884  rawSpace(areaSize); //called method also checks n <= maxSize()
885  store_->append(memArea, areaSize);
886  len_ += areaSize;
887  ++stats.append;
888  return *this;
889 }
890 
896 void
898 {
899  debugs(24, 8, id << " new size:" << newsize);
900  if (newsize == npos || newsize < length())
901  newsize = length();
902 
903  if (store_->LockCount() == 1 && newsize == length()) {
904  debugs(24, 8, id << " no cow needed");
905  ++stats.cowFast;
906  return;
907  }
908  reAlloc(newsize);
909 }
910 
const char * name
optional set label for debugging (default: "anonymous")
Definition: CharacterSet.h:69
uint64_t live
number of currently-allocated SBuf
Definition: Stats.h:51
~SBuf()
Definition: SBuf.cc:77
uint64_t chop
number of chop operations
Definition: Stats.h:45
#define Must2(condition, message)
Definition: TextException.h:59
std::ostream & dump(std::ostream &os) const
Definition: SBuf.cc:326
#define assert(EX)
Definition: assert.h:17
SBuf & appendf(const char *fmt,...)
Definition: SBuf.cc:248
static int memcasecmp(const char *b1, const char *b2, SBuf::size_type len)
Definition: SBuf.cc:360
SBuf & assign(const SBuf &S)
Definition: SBuf.cc:92
uint64_t toStream
number of write operations to ostreams
Definition: Stats.h:37
size_type idealSpace
if allocating anyway, provide this much space
Definition: SBuf.h:696
Definition: SBuf.h:87
uint64_t allocCopy
number of calls to SBuf copy-constructor
Definition: Stats.h:31
int i
Definition: membanger.c:49
SBuf & append(const SBuf &S)
Definition: SBuf.cc:204
size_type capacity
size of the raw allocated memory block
Definition: MemBlob.h:103
uint64_t assignFast
number of no-copy assignment operations
Definition: Stats.h:33
void * memrchr(const void *s, int c, size_t n)
Definition: memrchr.cc:36
static const SBufStats & GetStats()
gets global statistic informations
Definition: SBuf.cc:517
SBuf & chop(size_type pos, size_type n=npos)
Definition: SBuf.cc:553
std::ostream & print(std::ostream &os) const
print the SBuf contents to the supplied ostream
Definition: SBuf.cc:318
size_type findLastNotOf(const CharacterSet &set, size_type endPos=npos) const
Definition: SBuf.cc:813
bool canAppend(const size_type off, const size_type n) const
Definition: MemBlob.h:73
void clear()
Definition: SBuf.cc:187
#define Must(condition)
Like assert() but throws an exception instead of aborting the process.
Definition: TextException.h:69
void toUpper()
converts all characters to upper case;
Definition: SBuf.cc:847
bool isEmpty() const
Definition: SBuf.h:421
char * p
Definition: membanger.c:43
InstanceIdDefinitions(SBuf,"SBuf")
MemBlob::Pointer store_
memory block, possibly shared with other SBufs
Definition: SBuf.h:619
static const size_type maxSize
Maximum size of a SBuf. By design it MUST be < MAX(size_type)/2. Currently 256Mb. ...
Definition: SBuf.h:96
void checkAccessBounds(const size_type pos) const
Definition: SBuf.h:654
A const & max(A const &lhs, A const &rhs)
char * buf() const
Definition: SBuf.h:635
void setAt(size_type pos, char toset)
Definition: SBuf.cc:351
static MemBlob::Pointer GetStorePrototype()
Definition: SBuf.cc:85
SBuf & lowAppend(const char *memArea, size_type areaSize)
Definition: SBuf.cc:882
void rawAppendFinish(const char *start, size_type actualSize)
Definition: SBuf.cc:153
uint64_t append
number of append operations
Definition: Stats.h:35
void reAlloc(size_type newsize)
Definition: SBuf.cc:868
void toLower()
converts all characters to lower case;
Definition: SBuf.cc:834
SBufCaseSensitive
Definition: SBuf.h:37
Named SBuf::reserve() parameters. Defaults ask for and restrict nothing.
Definition: SBuf.h:686
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:405
char * rawAppendStart(size_type anticipatedSize)
Definition: SBuf.cc:145
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:121
size_type maxCapacity
do not allocate more than this
Definition: SBuf.h:698
uint64_t rawAccess
number of accesses to raw contents
Definition: Stats.h:43
uint64_t alloc
number of calls to SBuf constructors
Definition: Stats.h:30
bool operator!=(const SBuf &S) const
Definition: SBuf.cc:498
uint64_t trim
number of trim operations
Definition: Stats.h:46
SBuf & Printf(const char *fmt,...)
Definition: SBuf.cc:233
size_type off_
our content start offset from the beginning of shared store_
Definition: SBuf.h:620
char * bufEnd() const
Definition: SBuf.h:642
uint64_t clear
number of clear operations
Definition: Stats.h:34
uint64_t compareSlow
number of comparison operations requiring data scan
Definition: Stats.h:40
const char * c_str()
Definition: SBuf.cc:539
optimized set of C chars, with quick membership test and merge support
Definition: CharacterSet.h:17
bool allowShared
whether sharing our storage with others is OK
Definition: SBuf.h:699
int compare(const SBuf &S, const SBufCaseSensitive isCaseSensitive, const size_type n) const
Definition: SBuf.cc:375
std::ostream & dump(std::ostream &os) const
dump debugging information
Definition: MemBlob.cc:134
char * mem
raw allocated memory block
Definition: MemBlob.h:102
uint64_t copyOut
number of data-copies to other forms of buffers
Definition: Stats.h:42
SBuf consume(size_type n=npos)
Definition: SBuf.cc:504
int cur
Definition: ModDevPoll.cc:76
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
char * rawSpace(size_type minSize)
Definition: SBuf.cc:166
uint64_t find
number of find operations
Definition: Stats.h:47
void append(const char *source, const size_type n)
Definition: MemBlob.cc:116
uint64_t cowFast
number of cow operations not actually requiring a copy
Definition: Stats.h:49
size_type minSpace
allocate [at least this much] if spaceSize() is smaller
Definition: SBuf.h:697
size_type findFirstOf(const CharacterSet &set, size_type startPos=0) const
Definition: SBuf.cc:746
uint64_t caseChange
number of toUpper and toLower operations
Definition: Stats.h:48
void recordSBufSizeAtDestruct(SBuf::size_type sz)
Record the size a SBuf had when it was destructed.
void cow(size_type minsize=npos)
Definition: SBuf.cc:897
bool startsWith(const SBuf &S, const SBufCaseSensitive isCaseSensitive=caseSensitive) const
Definition: SBuf.cc:465
bool operator==(const SBuf &S) const
Definition: SBuf.cc:478
SBuf & trim(const SBuf &toRemove, bool atBeginning=true, bool atEnd=true)
Definition: SBuf.cc:574
uint64_t compareFast
number of comparison operations not requiring data scan
Definition: Stats.h:41
static const size_type npos
Definition: SBuf.h:93
size_type find(char c, size_type startPos=0) const
Definition: SBuf.cc:607
static SBufStats stats
class-wide statistics
Definition: SBuf.h:622
size_type len_
number of our content bytes in shared store_
Definition: SBuf.h:621
uint64_t setChar
number of calls to setAt
Definition: Stats.h:38
size_type rfind(char c, size_type endPos=npos) const
Definition: SBuf.cc:715
Definition: Debug.h:177
size_type findFirstNotOf(const CharacterSet &set, size_type startPos=0) const
Definition: SBuf.cc:769
void reserveCapacity(size_type minCapacity)
Definition: SBuf.cc:114
SBuf & vappendf(const char *fmt, va_list vargs)
Definition: SBuf.cc:258
const char * rawContent() const
Definition: SBuf.cc:532
uint64_t allocFromCString
number of copy-allocations from c-strings
Definition: Stats.h:32
size_type findLastOf(const CharacterSet &set, size_type endPos=npos) const
Definition: SBuf.cc:792
MemBlob::size_type size_type
Definition: SBuf.h:90
size_type size
maximum allocated memory in use by callers
Definition: MemBlob.h:104
size_type reserve(const SBufReservationRequirements &requirements)
Definition: SBuf.cc:121
uint64_t nulTerminate
number of c_str() terminations
Definition: Stats.h:44
SBuf substr(size_type pos, size_type n=npos) const
Definition: SBuf.cc:599
size_type copy(char *dest, size_type n) const
Definition: SBuf.cc:523
const InstanceId< SBuf > id
Definition: SBuf.h:594
#define NULL
Definition: types.h:166
SBuf()
create an empty (zero-size) SBuf
Definition: SBuf.cc:37
A const & min(A const &lhs, A const &rhs)
size_type spaceSize() const
Definition: SBuf.h:383
uint64_t cowSlow
number of cow operations requiring a copy
Definition: Stats.h:50
void clear()
extends the available space to the entire allocated blob
Definition: MemBlob.h:95

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors