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