]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/MemBuf.cc
2 * $Id: MemBuf.cc,v 1.8 1998/05/11 18:44:30 rousskov Exp $
4 * DEBUG: section 59 auto-growing Memory Buffer with printf
5 * AUTHOR: Alex Rousskov
7 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
8 * --------------------------------------------------------
10 * Squid is the result of efforts by numerous individuals from the
11 * Internet community. Development is led by Duane Wessels of the
12 * National Laboratory for Applied Network Research and funded by
13 * the National Science Foundation.
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32 * To-Do: uses memory pools for .buf recycling @?@ @?@
39 * Here is how one would comm_write an object without MemBuffer:
43 * buf = malloc(big_enough);
46 * snprintf object(s) piece-by-piece constantly checking for overflows
47 * and maintaining (buf+offset);
51 * comm_write(buf, free, ...);
54 * The whole "packing" idea is quite messy: We are given a buffer of fixed
55 * size and we have to check all the time that we still fit. Sounds logical.
56 * However, what happens if we have more data? If we are lucky to be careful
57 * to stop before we overrun any buffers, we still may have garbage (e.g.
58 * half of ETag) in the buffer.
63 * MemBuffer is a memory-resident buffer with printf()-like interface. It
64 * hides all offest handling and overflow checking. Moreover, it has a
65 * build-in control that no partial data has been written.
67 * MemBuffer is designed to handle relatively small data. It starts with a
68 * small buffer of configurable size to avoid allocating huge buffers all the
69 * time. MemBuffer doubles the buffer when needed. It assert()s that it will
70 * not grow larger than a configurable limit. MemBuffer has virtually no
71 * overhead (and can even reduce memory consumption) compared to old
74 * MemBuffer eliminates both "packing" mess and truncated data:
80 * -- required init with optional size tuning (see #defines for defaults)
81 * memBufInit(&buf, initial-size, absolute-maximum);
83 * -- "pack" (no need to handle offsets or check for overflows)
84 * memBufPrintf(&buf, ...);
88 * comm_write(buf.buf, memBufFreeFunc(&buf), ...);
90 * -- *iff* you did not give the buffer away, free it yourself
91 * -- memBufClean(&buf);
100 /* default values for buffer sizes, used by memBufDefInit */
101 #define MEM_BUF_INIT_SIZE (2*1024)
102 #define MEM_BUF_MAX_SIZE (32*1024)
106 static void memBufGrow(MemBuf
* mb
, mb_size_t min_cap
);
109 /* init with defaults */
111 memBufDefInit(MemBuf
* mb
)
113 memBufInit(mb
, MEM_BUF_INIT_SIZE
, MEM_BUF_MAX_SIZE
);
117 /* init with specific sizes */
119 memBufInit(MemBuf
* mb
, mb_size_t szInit
, mb_size_t szMax
)
122 assert(szInit
> 0 && szMax
> 0);
126 mb
->max_capacity
= szMax
;
130 memBufGrow(mb
, szInit
);
134 * cleans the mb; last function to call if you do not give .buf away with
138 memBufClean(MemBuf
* mb
)
142 assert(mb
->freefunc
); /* not frozen */
144 (*mb
->freefunc
) (mb
->buf
); /* freeze */
146 mb
->size
= mb
->capacity
= 0;
149 /* calls memcpy, appends exactly size bytes, extends buffer if needed */
151 memBufAppend(MemBuf
* mb
, const char *buf
, mb_size_t sz
)
153 assert(mb
&& buf
&& sz
>= 0);
155 assert(mb
->freefunc
); /* not frozen */
158 if (mb
->size
+ sz
> mb
->capacity
)
159 memBufGrow(mb
, mb
->size
+ sz
);
160 assert(mb
->size
+ sz
<= mb
->capacity
); /* paranoid */
161 xmemcpy(mb
->buf
+ mb
->size
, buf
, sz
);
166 /* calls snprintf, extends buffer if needed */
169 memBufPrintf(MemBuf
* mb
, const char *fmt
,...)
175 memBufPrintf(va_alist
)
180 const char *fmt
= NULL
;
183 mb
= va_arg(args
, MemBuf
*);
184 fmt
= va_arg(args
, char *);
186 memBufVPrintf(mb
, fmt
, args
);
191 /* vprintf for other printf()'s to use */
193 memBufVPrintf(MemBuf
* mb
, const char *fmt
, va_list vargs
)
198 assert(mb
->freefunc
); /* not frozen */
199 /* @?@ we do not init buf with '\0', do we have to for vsnprintf?? @?@ */
200 /* assert in Grow should quit first, but we do not want to have a scare (1) loop */
201 while (mb
->capacity
<= mb
->max_capacity
) {
202 mb_size_t free_space
= mb
->capacity
- mb
->size
;
203 /* put as much as we can */
204 sz
= vsnprintf(mb
->buf
+ mb
->size
, free_space
, fmt
, vargs
) + 1;
205 /* check for possible overflow @?@ can vsnprintf cut more than needed off? */
206 if (sz
+ 32 >= free_space
) /* magic constant 32, ARGH! @?@ */
207 memBufGrow(mb
, mb
->capacity
+ 1);
211 mb
->size
+= sz
- 1; /* note that we cut 0-terminator as store does @?@ @?@ */
215 * returns free() function to be used.
217 * calling this function "freezes" mb,
218 * do not _update_ mb after that in any way
219 * (you still can read-access .buf and .size)
222 memBufFreeFunc(MemBuf
* mb
)
227 assert(mb
->freefunc
); /* not frozen */
230 mb
->freefunc
= NULL
; /* freeze */
234 /* grows (doubles) internal buffer to satisfy required minimal capacity */
236 memBufGrow(MemBuf
* mb
, mb_size_t min_cap
)
240 assert(mb
->capacity
< min_cap
);
242 /* determine next capacity */
243 new_cap
= mb
->capacity
;
245 while (new_cap
< min_cap
)
246 new_cap
*= 2; /* double */
250 /* last chance to fit before we assert(!overflow) */
251 if (new_cap
> mb
->max_capacity
)
252 new_cap
= mb
->max_capacity
;
254 assert(new_cap
<= mb
->max_capacity
); /* no overflow */
255 assert(new_cap
> mb
->capacity
); /* progress */
257 /* finally [re]allocate memory */
259 mb
->buf
= xmalloc(new_cap
);
260 mb
->freefunc
= &xfree
;
262 assert(mb
->freefunc
== &xfree
); /* for now */
263 mb
->buf
= xrealloc(mb
->buf
, new_cap
);
265 memset(mb
->buf
+ mb
->size
, 0, new_cap
- mb
->size
); /* just in case */
266 mb
->capacity
= new_cap
;
272 /* puts report on MemBuf _module_ usage into mb */
274 memBufReport(MemBuf
* mb
)
277 memBufPrintf(mb
, "memBufReport is not yet implemented @?@\n");