/*
- * $Id: MemBuf.cc,v 1.43 2008/02/26 21:49:34 amosjeffries Exp $
+ * $Id$
*
* DEBUG: section 59 auto-growing Memory Buffer with printf
* AUTHOR: Alex Rousskov
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
\verbatim
* Rationale:
* ----------
- *
- * Here is how one would comm_write an object without MemBuffer:
- *
+ *
+ * Here is how one would Comm::Write an object without MemBuffer:
+ *
* {
* -- allocate:
* buf = malloc(big_enough);
- *
+ *
* -- "pack":
* snprintf object(s) piece-by-piece constantly checking for overflows
* and maintaining (buf+offset);
* ...
- *
+ *
* -- write
- * comm_write(buf, free, ...);
+ * Comm::Write(buf, free, ...);
* }
- *
+ *
* The whole "packing" idea is quite messy: We are given a buffer of fixed
* size and we have to check all the time that we still fit. Sounds logical.
*
* However, what happens if we have more data? If we are lucky to stop before
* we overrun any buffers, we still may have garbage (e.g. half of ETag) in
* the buffer.
- *
+ *
* MemBuffer:
* ----------
- *
+ *
* MemBuffer is a memory-resident buffer with printf()-like interface. It
* hides all offest handling and overflow checking. Moreover, it has a
* build-in control that no partial data has been written.
- *
+ *
* MemBuffer is designed to handle relatively small data. It starts with a
* small buffer of configurable size to avoid allocating huge buffers all the
* time. MemBuffer doubles the buffer when needed. It assert()s that it will
* not grow larger than a configurable limit. MemBuffer has virtually no
* overhead (and can even reduce memory consumption) compared to old
* "packing" approach.
- *
+ *
* MemBuffer eliminates both "packing" mess and truncated data:
- *
+ *
* {
* -- setup
* MemBuf buf;
- *
+ *
* -- required init with optional size tuning (see #defines for defaults)
* buf.init(initial-size, absolute-maximum);
- *
+ *
* -- "pack" (no need to handle offsets or check for overflows)
* buf.Printf(...);
* ...
- *
+ *
* -- write
- * comm_write_mbuf(fd, buf, handler, data);
+ * Comm::Write(fd, buf, callback);
*
* -- *iff* you did not give the buffer away, free it yourself
* -- buf.clean();
\endverbatim
*/
-/* if you have configure you can use this */
-#if defined(HAVE_CONFIG_H)
-#include "config.h"
-#endif
+#include "squid.h"
+#include "MemBuf.h"
+#include "profiler/Profiler.h"
+#include "protos.h"
#ifdef VA_COPY
#undef VA_COPY
#define VA_COPY __va_copy
#endif
-#include "squid.h"
-#include "MemBuf.h"
-
/* local constants */
/* default values for buffer sizes, used by memBufDefInit */
init(MEM_BUF_INIT_SIZE, MEM_BUF_MAX_SIZE);
}
-
/** init with specific sizes */
void
MemBuf::init(mb_size_t szInit, mb_size_t szMax)
PROF_start(MemBuf_consume);
if (shiftSize > 0) {
if (shiftSize < cSize)
- xmemmove(buf, buf + shiftSize, cSize - shiftSize);
+ memmove(buf, buf + shiftSize, cSize - shiftSize);
size -= shiftSize;
PROF_stop(MemBuf_consume);
}
-// calls memcpy, appends exactly size bytes, extends buffer if needed
+// removes last tailSize bytes
+void MemBuf::truncate(mb_size_t tailSize)
+{
+ const mb_size_t cSize = contentSize();
+ assert(0 <= tailSize && tailSize <= cSize);
+ assert(!stolen); /* not frozen */
+ size -= tailSize;
+}
+
+/**
+ * calls memcpy, appends exactly size bytes,
+ * extends buffer or creates buffer if needed.
+ */
void MemBuf::append(const char *newContent, mb_size_t sz)
{
assert(sz >= 0);
- assert(buf);
+ assert(buf || (0==capacity && 0==size));
assert(!stolen); /* not frozen */
PROF_start(MemBuf_append);
grow(size + sz + 1);
assert(size + sz <= capacity); /* paranoid */
-
- xmemcpy(space(), newContent, sz);
-
+ memcpy(space(), newContent, sz);
appended(sz);
}
PROF_stop(MemBuf_append);
}
-// updates content size after external append
+/// updates content size after external append
void MemBuf::appended(mb_size_t sz)
{
assert(size + sz <= capacity);
}
/* calls memBufVPrintf */
-#if STDC_HEADERS
void
MemBuf::Printf(const char *fmt,...)
{
va_list args;
va_start(args, fmt);
-#else
-void
-MemBuf::Printf(va_alist)
-va_dcl
-{
- va_list args;
- mb_size_t sz = 0;
- va_start(args);
- const char *fmt = va_arg(args, char *);
-#endif
-
vPrintf(fmt, args);
va_end(args);
}
-
/**
* vPrintf for other printf()'s to use; calls vsnprintf, extends buf if needed
*/
void
-MemBuf::vPrintf(const char *fmt, va_list vargs) {
+MemBuf::vPrintf(const char *fmt, va_list vargs)
+{
#ifdef VA_COPY
va_list ap;
#endif
if (!size || buf[size - 1]) {
assert(!buf[size]);
} else {
- size--;
+ --size;
}
}
\retval free() function to be used.
*/
FREE *
-MemBuf::freeFunc() {
+MemBuf::freeFunc()
+{
FREE *ff;
assert(buf);
assert(!stolen); /* not frozen */
* Grows (doubles) internal buffer to satisfy required minimal capacity
*/
void
-MemBuf::grow(mb_size_t min_cap) {
+MemBuf::grow(mb_size_t min_cap)
+{
size_t new_cap;
size_t buf_cap;
PROF_stop(MemBuf_grow);
}
-
/* Reports */
/**
* Puts report on MemBuf _module_ usage into mb
*/
void
-memBufReport(MemBuf * mb) {
+memBufReport(MemBuf * mb)
+{
assert(mb);
mb->Printf("memBufReport is not yet implemented @?@\n");
}
-#ifndef _USE_INLINE_
+#if !_USE_INLINE_
#include "MemBuf.cci"
#endif