9 #include "wvbufstore.h"
11 #include <sys/types.h>
26 memcpy(target, source, count);
29 inline void copy(
void *target,
const void *source,
size_t count)
32 memcpy(target, source, count);
41 memmove(target, source, count);
45 inline void swap(
void *target,
void *source,
size_t count)
47 register unsigned char *t1 = (
unsigned char*)target;
48 register unsigned char *t2 = (
unsigned char*)source;
51 register unsigned char temp;
58 inline void uninit(
void *target,
size_t count)
64 return new unsigned char[count];
74 inline size_t roundup(
size_t value,
size_t boundary)
76 size_t mod = value % boundary;
77 return mod ? value + boundary - mod : value;
84 WvBufStore::WvBufStore(
int _granularity) :
85 granularity(_granularity)
90 size_t WvBufStore::peekable(
int offset)
const
98 if (
size_t(-offset) <= ungettable())
99 return size_t(-offset) + used();
103 int avail = int(used()) - offset;
111 void WvBufStore::move(
void *buf,
size_t count)
115 size_t amount = count;
116 assert(amount != 0 ||
117 !
"attempted to move() more than used()");
120 const void *data = get(amount);
122 buf = (
unsigned char*)buf + amount;
128 void WvBufStore::copy(
void *buf,
int offset,
size_t count)
132 size_t amount = optpeekable(offset);
133 assert(amount != 0 ||
134 !
"attempted to copy() with invalid offset");
137 const void *data = peek(offset, amount);
139 buf = (
unsigned char*)buf + amount;
146 void WvBufStore::put(
const void *data,
size_t count)
150 size_t amount = optallocable();
151 assert(amount != 0 ||
152 !
"attempted to put() more than free()");
155 void *buf = alloc(amount);
157 data = (
const unsigned char*)data + amount;
163 void WvBufStore::fastput(
const void *data,
size_t count)
165 void *buf = alloc(count);
170 void WvBufStore::poke(
const void *data,
int offset,
size_t count)
172 int limit = int(used());
173 assert(offset <= limit ||
174 !
"attempted to poke() beyond end of buffer");
175 int end = offset + count;
178 size_t tail = end - limit;
180 put((
const unsigned char*)data + count, tail);
184 size_t amount = optpeekable(offset);
185 assert(amount != 0 ||
186 !
"attempted to poke() with invalid offset");
189 void *buf = mutablepeek(offset, amount);
190 memops.
copy(buf, data, amount);
191 data = (
const unsigned char*)data + amount;
198 void WvBufStore::merge(
WvBufStore &instore,
size_t count)
212 size_t avail = buf->used();
225 basicmerge(instore, count);
229 void WvBufStore::basicmerge(
WvBufStore &instore,
size_t count)
234 const void *indata = NULL;
235 void *outdata = NULL;
242 inavail = instore.optgettable();
243 assert(inavail != 0 ||
244 !
"attempted to merge() more than instore.used()");
247 indata = instore.get(inavail);
251 outavail = optallocable();
252 assert(outavail != 0 ||
253 !
"attempted to merge() more than free()");
254 if (outavail > count)
256 outdata = alloc(outavail);
258 if (inavail < outavail)
268 outdata = (
unsigned char*)outdata + inavail;
275 if (count == 0)
return;
277 indata = (
const unsigned char*)indata + outavail;
287 WvInPlaceBufStore::WvInPlaceBufStore(
int _granularity,
288 void *_data,
size_t _avail,
size_t _size,
bool _autofree) :
291 reset(_data, _avail, _size, _autofree);
295 WvInPlaceBufStore::WvInPlaceBufStore(
int _granularity,
size_t _size) :
298 reset(memops.
newarray(_size), 0, _size,
true);
302 WvInPlaceBufStore::~WvInPlaceBufStore()
304 if (data && xautofree)
309 void WvInPlaceBufStore::reset(
void *_data,
size_t _avail,
310 size_t _size,
bool _autofree =
false)
312 assert(_data != NULL || _avail == 0);
313 if (data && _data != data && xautofree)
316 xautofree = _autofree;
322 void WvInPlaceBufStore::setavail(
size_t _avail)
324 assert(_avail <= xsize);
330 size_t WvInPlaceBufStore::used()
const
332 return writeidx - readidx;
336 const void *WvInPlaceBufStore::get(
size_t count)
338 assert(count <= writeidx - readidx ||
339 !
"attempted to get() more than used()");
340 const void *tmpptr = (
const unsigned char*)data + readidx;
346 void WvInPlaceBufStore::unget(
size_t count)
348 assert(count <= readidx ||
349 !
"attempted to unget() more than ungettable()");
354 size_t WvInPlaceBufStore::ungettable()
const
360 void WvInPlaceBufStore::zap()
362 readidx = writeidx = 0;
366 size_t WvInPlaceBufStore::free()
const
368 return xsize - writeidx;
372 void *WvInPlaceBufStore::alloc(
size_t count)
374 assert(count <= xsize - writeidx ||
375 !
"attempted to alloc() more than free()");
376 void *tmpptr = (
unsigned char*)data + writeidx;
382 void WvInPlaceBufStore::unalloc(
size_t count)
384 assert(count <= writeidx - readidx ||
385 !
"attempted to unalloc() more than unallocable()");
390 size_t WvInPlaceBufStore::unallocable()
const
392 return writeidx - readidx;
396 void *WvInPlaceBufStore::mutablepeek(
int offset,
size_t count)
400 assert(((offset <= 0) ?
401 size_t(-offset) <= readidx :
402 size_t(offset) < writeidx - readidx) ||
403 !
"attempted to peek() with invalid offset or count");
404 return (
unsigned char*)data + readidx + offset;
411 WvConstInPlaceBufStore::WvConstInPlaceBufStore(
int _granularity,
412 const void *_data,
size_t _avail) :
415 reset(_data, _avail);
419 void WvConstInPlaceBufStore::reset(
const void *_data,
size_t _avail)
421 assert(_data != NULL || _avail == 0);
427 size_t WvConstInPlaceBufStore::used()
const
429 return avail - readidx;
433 void WvConstInPlaceBufStore::setavail(
size_t _avail)
440 const void *WvConstInPlaceBufStore::get(
size_t count)
442 assert(count <= avail - readidx ||
443 !
"attempted to get() more than used()");
444 const void *ptr = (
const unsigned char*)data + readidx;
450 void WvConstInPlaceBufStore::unget(
size_t count)
452 assert(count <= readidx ||
453 !
"attempted to unget() more than ungettable()");
458 size_t WvConstInPlaceBufStore::ungettable()
const
464 const void *WvConstInPlaceBufStore::peek(
int offset,
size_t count)
468 assert(((offset <= 0) ?
469 size_t(-offset) <= readidx :
470 size_t(offset) < avail - readidx) ||
471 !
"attempted to peek() with invalid offset or count");
472 return (
const unsigned char*)data + readidx + offset;
476 void WvConstInPlaceBufStore::zap()
485 WvCircularBufStore::WvCircularBufStore(
int _granularity,
486 void *_data,
size_t _avail,
size_t _size,
bool _autofree) :
489 reset(_data, _avail, _size, _autofree);
493 WvCircularBufStore::WvCircularBufStore(
int _granularity,
size_t _size) :
496 reset(memops.
newarray(_size), 0, _size,
true);
500 WvCircularBufStore::~WvCircularBufStore()
502 if (data && xautofree)
507 void WvCircularBufStore::reset(
void *_data,
size_t _avail,
508 size_t _size,
bool _autofree =
false)
510 assert(_data != NULL || _avail == 0);
511 if (data && _data != data && xautofree)
514 xautofree = _autofree;
520 void WvCircularBufStore::setavail(
size_t _avail)
522 assert(_avail <= xsize);
524 totalused = totalinit = _avail;
528 size_t WvCircularBufStore::used()
const
534 size_t WvCircularBufStore::optgettable()
const
536 size_t avail = xsize - head;
537 if (avail > totalused)
543 const void *WvCircularBufStore::get(
size_t count)
545 assert(count <= totalused ||
546 !
"attempted to get() more than used()");
548 const void *tmpptr = (
const unsigned char*)data + first;
549 head = (head + count) % xsize;
555 void WvCircularBufStore::unget(
size_t count)
557 assert(count <= totalinit - totalused ||
558 !
"attempted to unget() more than ungettable()");
559 head = (head + xsize - count) % xsize;
564 size_t WvCircularBufStore::ungettable()
const
566 return totalinit - totalused;
570 void WvCircularBufStore::zap()
573 totalused = totalinit = 0;
577 size_t WvCircularBufStore::free()
const
579 return xsize - totalused;
583 size_t WvCircularBufStore::optallocable()
const
585 size_t tail = head + totalused;
587 return xsize - totalused;
592 void *WvCircularBufStore::alloc(
size_t count)
594 assert(count <= xsize - totalused ||
595 !
"attempted to alloc() more than free()");
596 totalinit = totalused;
599 void *tmpptr = (
unsigned char*)data + first;
606 void WvCircularBufStore::unalloc(
size_t count)
608 assert(count <= totalused ||
609 !
"attempted to unalloc() more than unallocable()");
615 size_t WvCircularBufStore::unallocable()
const
621 void *WvCircularBufStore::mutablepeek(
int offset,
size_t count)
625 assert(((offset <= 0) ?
626 size_t(-offset) <= totalinit - totalused :
627 size_t(offset) < totalused) ||
628 !
"attempted to peek() with invalid offset or count");
631 void *tmpptr = (
unsigned char*)data + first;
636 void WvCircularBufStore::normalize()
639 totalinit = totalused;
642 compact(data, xsize, head, totalused);
648 size_t count,
bool keephistory)
651 size_t start = (head + offset + xsize) % xsize;
654 size_t end = start + count;
659 size_t keepstart = head;
663 keepstart += totalused - totalinit + xsize;
668 totalinit = totalused;
673 compact(data, xsize, keepstart, totalinit);
674 head = totalinit - totalused;
677 start = (head + offset + xsize) % xsize;
685 size_t head,
size_t count)
694 if (head + count <= size)
698 memops.
uninit_move(data, (
unsigned char*)data + head, count);
702 size_t headcount = size - head;
703 size_t tailcount = count - headcount;
704 size_t freecount = size - count;
705 if (freecount >= headcount)
709 memops.
uninit_move((
unsigned char*)data + headcount,
711 memops.
uninit_move(data, (
unsigned char*)data + head,
718 unsigned char *start = (
unsigned char*)data;
719 unsigned char *end = (
unsigned char*)data + head;
720 while (tailcount >= headcount)
722 memops.
swap(start, end, headcount);
724 tailcount -= headcount;
728 void *buf = memops.
newarray(tailcount);
731 memops.
uninit_move(start + headcount, buf, tailcount);
739 WvLinkedBufferStore::WvLinkedBufferStore(
int _granularity) :
740 WvBufStore(_granularity), totalused(0), maxungettable(0)
766 list.append(buffer, autofree);
767 totalused += buffer->used();
774 list.prepend(buffer, autofree);
775 totalused += buffer->used();
783 WvBufStoreList::Iter it(list);
784 WvLink *link = it.find(buffer);
787 bool autofree = it.get_autofree();
788 totalused -= buffer->used();
789 if (buffer == list.first())
792 it.set_autofree(
false);
798 size_t WvLinkedBufferStore::used()
const
800 assert(!totalused || !list.isempty());
805 size_t WvLinkedBufferStore::optgettable()
const
809 WvBufStoreList::Iter it(list);
810 for (it.rewind(); it.next(); )
811 if ((count = it->optgettable()) != 0)
817 const void *WvLinkedBufferStore::get(
size_t count)
819 assert(!totalused || !list.isempty());
823 assert(count <= totalused);
828 assert(totalused >= 0);
833 WvBufStoreList::Iter it(list);
836 it.rewind(); it.next();
838 assert(buf &&
"attempted to get() more than used()" &&
839 "totalused is wrong!");
841 availused = buf->used();
850 if (availused < count)
853 maxungettable += count;
854 return buf->get(count);
858 void WvLinkedBufferStore::unget(
size_t count)
860 assert(!totalused || !list.isempty());
864 assert(!list.isempty());
865 assert(count <= maxungettable);
867 maxungettable -= count;
868 list.first()->unget(count);
872 size_t WvLinkedBufferStore::ungettable()
const
874 assert(!totalused || !list.isempty());
877 assert(maxungettable == 0);
889 size_t avail = list.first()->ungettable();
890 if (avail > maxungettable)
891 avail = maxungettable;
896 void WvLinkedBufferStore::zap()
900 WvBufStoreList::Iter it(list);
901 for (it.rewind(); it.next(); )
906 size_t WvLinkedBufferStore::free()
const
909 return list.last()->free();
914 size_t WvLinkedBufferStore::optallocable()
const
917 return list.last()->optallocable();
922 void *WvLinkedBufferStore::alloc(
size_t count)
926 assert(!list.isempty() &&
"attempted to alloc() more than free()");
928 return list.last()->alloc(count);
932 void WvLinkedBufferStore::unalloc(
size_t count)
934 assert(count <= totalused);
939 assert(!list.isempty() &&
940 "attempted to unalloc() more than unallocable()" &&
941 "totalused is wrong");
943 size_t avail = buf->unallocable();
950 WvBufStoreList::Iter it(list);
959 size_t WvLinkedBufferStore::unallocable()
const
965 size_t WvLinkedBufferStore::optpeekable(
int offset)
const
968 WvBufStoreList::Iter it(list);
969 int newoffset =
search(it, offset);
973 return buf->optpeekable(newoffset);
977 void *WvLinkedBufferStore::mutablepeek(
int offset,
size_t count)
983 WvBufStoreList::Iter it(list);
984 offset =
search(it, offset);
986 assert(buf &&
"attempted to peek() with invalid offset or count");
989 size_t availpeek = buf->peekable(offset);
990 if (availpeek < count)
992 return buf->mutablepeek(offset, count);
998 minsize = roundup(minsize, granularity);
1020 if (
size_t(-offset) <= buf->ungettable())
1030 size_t avail = buf->used();
1031 if (
size_t(offset) < avail)
1046 size_t availused = buf->used();
1047 if (count <= availused)
1051 size_t needed = count - availused;
1052 size_t availfree = buf->free();
1053 size_t mustskip = 0;
1054 if (availfree < needed)
1059 if (buf == list.first() && totalused != 0)
1064 mustskip = ungettable();
1065 buf->unget(mustskip);
1068 needed = count + mustskip;
1072 list.add_after(it.prev, buf,
true);
1080 size_t chunk = itbuf->used();
1085 buf->merge(*itbuf, chunk);
1089 buf->skip(mustskip);
1095 assert(
false &&
"invalid count during get() or peek()");
1100 void WvLinkedBufferStore::do_xunlink(WvBufStoreList::Iter &it)
1103 if (buf == list.first())
1106 bool autofree = it.get_autofree();
1107 it.set_autofree(
false);
1117 WvDynBufStore::WvDynBufStore(
size_t _granularity,
1118 size_t _minalloc,
size_t _maxalloc) :
1120 minalloc(_minalloc), maxalloc(_maxalloc)
1122 assert(maxalloc >= minalloc);
1126 size_t WvDynBufStore::free()
const
1128 return UNLIMITED_FREE_SPACE;
1132 size_t WvDynBufStore::optallocable()
const
1134 size_t avail = WvLinkedBufferStore::optallocable();
1136 avail = UNLIMITED_FREE_SPACE;
1141 void *WvDynBufStore::alloc(
size_t count)
1143 if (count > WvLinkedBufferStore::free())
1148 return WvLinkedBufferStore::alloc(count);
1157 size_t size = used();
1158 if (size < minsize * 2)
1160 if (size < minalloc)
1162 else if (size > maxalloc)
1173 WvNullBufStore::WvNullBufStore(
size_t _granularity) :
1183 WvBufCursorStore::WvBufCursorStore(
size_t _granularity,
1184 WvBufStore *_buf,
int _start,
size_t _length) :
1186 buf(_buf), start(_start), length(_length), shift(0)
1191 bool WvBufCursorStore::isreadable()
const
1193 return buf->isreadable();
1197 size_t WvBufCursorStore::used()
const
1199 return length - shift;
1203 size_t WvBufCursorStore::optgettable()
const
1205 size_t avail = buf->optpeekable(start + shift);
1206 assert(avail != 0 || length == shift ||
1207 !
"buffer cursor operating over invalid region");
1214 const void *WvBufCursorStore::get(
size_t count)
1216 assert(count <= length - shift ||
1217 !
"attempted to get() more than used()");
1218 const void *data = buf->peek(start + shift, count);
1224 void WvBufCursorStore::skip(
size_t count)
1226 assert(count <= length - shift ||
1227 !
"attempted to skip() more than used()");
1232 void WvBufCursorStore::unget(
size_t count)
1234 assert(count <= shift ||
1235 !
"attempted to unget() more than ungettable()");
1240 size_t WvBufCursorStore::ungettable()
const
1246 void WvBufCursorStore::zap()
1252 size_t WvBufCursorStore::peekable(
int offset)
const
1256 if (offset < 0 || offset >
int(length))
1258 return length - size_t(offset);
1262 size_t WvBufCursorStore::optpeekable(
int offset)
const
1264 size_t avail = buf->optpeekable(start + shift + offset);
1265 assert(avail != 0 || length == shift ||
1266 !
"buffer cursor operating over invalid region");
1267 size_t max = peekable(offset);
1274 const void *WvBufCursorStore::peek(
int offset,
size_t count)
1277 assert((offset >= start && offset - start + count <= length) ||
1278 !
"attempted to peek() with invalid offset or count");
1279 return buf->peek(offset, count);
1283 bool WvBufCursorStore::iswritable()
const
1286 return buf->iswritable();
1290 void *WvBufCursorStore::mutablepeek(
int offset,
size_t count)
1293 assert((offset >= start && offset - start + count <= length) ||
1294 !
"attempted to peek() with invalid offset or count");
1295 return buf->mutablepeek(offset, count);