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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors