00001
00002
00003
00004
00005
00006
00007
00008
00009
#include "wvbufstore.h"
00010
#include <string.h>
00011
#include <sys/types.h>
00012
00013
00014
00015
00016
00017
00018
00019
00020
struct MemOps
00021 {
00022
00023
inline void uninit_copy(
void *target,
const void *source,
00024 size_t count)
00025 {
00026 memcpy(target, source, count);
00027 }
00028
00029
inline void copy(
void *target,
const void *source, size_t count)
00030 {
00031 uninit(target, count);
00032 memcpy(target, source, count);
00033 }
00034
00035
00036
00037
00038
inline void uninit_move(
void *target,
void *source,
00039 size_t count)
00040 {
00041 memmove(target, source, count);
00042 uninit(source, count);
00043 }
00044
00045
inline void swap(
void *target,
void *source, size_t count)
00046 {
00047
register unsigned char *t1 = (
unsigned char*)target;
00048
register unsigned char *t2 = (
unsigned char*)source;
00049
while (count-- > 0)
00050 {
00051
register unsigned char temp;
00052 temp = *t1;
00053 *(t1++) = *t2;
00054 *(t2++) = temp;
00055 }
00056 }
00057
00058
inline void uninit(
void *target, size_t count)
00059 {
00060 }
00061
00062
inline void *newarray(size_t count)
00063 {
00064
return new unsigned char[count];
00065 }
00066
00067
inline void deletearray(
void *buf)
00068 {
00069
delete[] (
unsigned char*)buf;
00070 }
00071 }
memops;
00072
00073
00074 inline size_t
roundup(size_t value, size_t boundary)
00075 {
00076 size_t mod = value % boundary;
00077
return mod ? value + boundary - mod : value;
00078 }
00079
00080
00081
00082
00083
00084 WvBufStore::WvBufStore(
int _granularity) :
00085 granularity(_granularity)
00086 {
00087 }
00088
00089
00090 size_t
WvBufStore::peekable(
int offset)
const
00091
{
00092
if (offset == 0)
00093 {
00094
return used();
00095 }
00096
else if (offset < 0)
00097 {
00098
if (size_t(-offset) <=
ungettable())
00099
return size_t(-offset) +
used();
00100 }
00101
else
00102 {
00103
int avail = int(
used()) - offset;
00104
if (avail > 0)
00105
return avail;
00106 }
00107
return 0;
00108 }
00109
00110
00111 void WvBufStore::move(
void *buf, size_t count)
00112 {
00113
while (count > 0)
00114 {
00115 size_t amount =
optgettable();
00116 assert(amount != 0 ||
00117 !
"attempted to move() more than used()");
00118
if (amount > count)
00119 amount = count;
00120
const void *data =
get(amount);
00121
memops.uninit_copy(buf, data, amount);
00122 buf = (
unsigned char*)buf + amount;
00123 count -= amount;
00124 }
00125 }
00126
00127
00128 void WvBufStore::copy(
void *buf,
int offset, size_t count)
00129 {
00130
while (count > 0)
00131 {
00132 size_t amount =
optpeekable(offset);
00133 assert(amount != 0 ||
00134 !
"attempted to copy() with invalid offset");
00135
if (amount > count)
00136 amount = count;
00137
const void *data =
peek(offset, amount);
00138
memops.uninit_copy(buf, data, amount);
00139 buf = (
unsigned char*)buf + amount;
00140 count -= amount;
00141 offset += amount;
00142 }
00143 }
00144
00145
00146 void WvBufStore::put(
const void *data, size_t count)
00147 {
00148
while (count > 0)
00149 {
00150 size_t amount =
optallocable();
00151 assert(amount != 0 ||
00152 !
"attempted to put() more than free()");
00153
if (amount > count)
00154 amount = count;
00155
void *buf =
alloc(amount);
00156
memops.uninit_copy(buf, data, amount);
00157 data = (
const unsigned char*)data + amount;
00158 count -= amount;
00159 }
00160 }
00161
00162
00163 void WvBufStore::fastput(
const void *data, size_t count)
00164 {
00165
void *buf =
alloc(count);
00166
memops.uninit_copy(buf, data, count);
00167 }
00168
00169
00170 void WvBufStore::poke(
const void *data,
int offset, size_t count)
00171 {
00172
int limit = int(
used());
00173 assert(offset <= limit ||
00174 !
"attempted to poke() beyond end of buffer");
00175
int end = offset + count;
00176
if (end >= limit)
00177 {
00178 size_t tail = end - limit;
00179 count -= tail;
00180
put((
const unsigned char*)data + count, tail);
00181 }
00182
while (count > 0)
00183 {
00184 size_t amount =
optpeekable(offset);
00185 assert(amount != 0 ||
00186 !
"attempted to poke() with invalid offset");
00187
if (amount > count)
00188 amount = count;
00189
void *buf =
mutablepeek(offset, amount);
00190
memops.copy(buf, data, amount);
00191 data = (
const unsigned char*)data + amount;
00192 count -= amount;
00193 offset += amount;
00194 }
00195 }
00196
00197
00198 void WvBufStore::merge(
WvBufStore &instore, size_t count)
00199 {
00200
if (count == 0)
00201
return;
00202
00203
if (
usessubbuffers() && instore.
usessubbuffers())
00204 {
00205
00206
for (;;)
00207 {
00208
WvBufStore *buf = instore.
firstsubbuffer();
00209
if (! buf)
00210
break;
00211
00212 size_t avail = buf->
used();
00213
if (avail > count)
00214
break;
00215
00216
00217
bool autofree = instore.
unlinksubbuffer(buf,
false);
00218
appendsubbuffer(buf, autofree);
00219 count -= avail;
00220
if (count == 0)
00221
return;
00222 }
00223 }
00224
00225
basicmerge(instore, count);
00226 }
00227
00228
00229 void WvBufStore::basicmerge(
WvBufStore &instore, size_t count)
00230 {
00231
00232
if (count == 0)
00233
return;
00234
const void *indata = NULL;
00235
void *outdata = NULL;
00236 size_t inavail = 0;
00237 size_t outavail = 0;
00238
for (;;)
00239 {
00240
if (inavail == 0)
00241 {
00242 inavail = instore.
optgettable();
00243 assert(inavail != 0 ||
00244 !
"attempted to merge() more than instore.used()");
00245
if (inavail > count)
00246 inavail = count;
00247 indata = instore.
get(inavail);
00248 }
00249
if (outavail == 0)
00250 {
00251 outavail =
optallocable();
00252 assert(outavail != 0 ||
00253 !
"attempted to merge() more than free()");
00254
if (outavail > count)
00255 outavail = count;
00256 outdata =
alloc(outavail);
00257 }
00258
if (inavail < outavail)
00259 {
00260
memops.uninit_copy(outdata, indata, inavail);
00261 count -= inavail;
00262 outavail -= inavail;
00263
if (count == 0)
00264 {
00265
unalloc(outavail);
00266
return;
00267 }
00268 outdata = (
unsigned char*)outdata + inavail;
00269 inavail = 0;
00270 }
00271
else
00272 {
00273
memops.uninit_copy(outdata, indata, outavail);
00274 count -= outavail;
00275
if (count == 0)
return;
00276 inavail -= outavail;
00277 indata = (
const unsigned char*)indata + outavail;
00278 outavail = 0;
00279 }
00280 }
00281 }
00282
00283
00284
00285
00286
00287 WvInPlaceBufStore::WvInPlaceBufStore(
int _granularity,
00288
void *_data, size_t _avail, size_t _size,
bool _autofree) :
00289
WvBufStore(_granularity), data(NULL)
00290 {
00291
reset(_data, _avail, _size, _autofree);
00292 }
00293
00294
00295 WvInPlaceBufStore::WvInPlaceBufStore(
int _granularity, size_t _size) :
00296
WvBufStore(_granularity), data(NULL)
00297 {
00298
reset(
memops.newarray(_size), 0, _size,
true);
00299 }
00300
00301
00302 WvInPlaceBufStore::~WvInPlaceBufStore()
00303 {
00304
if (
data &&
xautofree)
00305
memops.deletearray(
data);
00306 }
00307
00308
00309 void WvInPlaceBufStore::reset(
void *_data, size_t _avail,
00310 size_t _size,
bool _autofree =
false)
00311 {
00312 assert(_data != NULL || _avail == 0);
00313
if (
data && _data !=
data &&
xautofree)
00314
memops.deletearray(
data);
00315
data = _data;
00316
xautofree = _autofree;
00317
xsize = _size;
00318
setavail(_avail);
00319 }
00320
00321
00322 void WvInPlaceBufStore::setavail(size_t _avail)
00323 {
00324 assert(_avail <=
xsize);
00325
readidx = 0;
00326
writeidx = _avail;
00327 }
00328
00329
00330 size_t
WvInPlaceBufStore::used()
const
00331
{
00332
return writeidx -
readidx;
00333 }
00334
00335
00336 const void *
WvInPlaceBufStore::get(size_t count)
00337 {
00338 assert(count <=
writeidx -
readidx ||
00339 !
"attempted to get() more than used()");
00340
const void *tmpptr = (
const unsigned char*)
data + readidx;
00341 readidx += count;
00342
return tmpptr;
00343 }
00344
00345
00346 void WvInPlaceBufStore::unget(size_t count)
00347 {
00348 assert(count <=
readidx ||
00349 !
"attempted to unget() more than ungettable()");
00350 readidx -= count;
00351 }
00352
00353
00354 size_t
WvInPlaceBufStore::ungettable()
const
00355
{
00356
return readidx;
00357 }
00358
00359
00360 void WvInPlaceBufStore::zap()
00361 {
00362
readidx =
writeidx = 0;
00363 }
00364
00365
00366 size_t
WvInPlaceBufStore::free()
const
00367
{
00368
return xsize -
writeidx;
00369 }
00370
00371
00372 void *
WvInPlaceBufStore::alloc(size_t count)
00373 {
00374 assert(count <=
xsize -
writeidx ||
00375 !
"attempted to alloc() more than free()");
00376
void *tmpptr = (
unsigned char*)
data + writeidx;
00377 writeidx += count;
00378
return tmpptr;
00379 }
00380
00381
00382 void WvInPlaceBufStore::unalloc(size_t count)
00383 {
00384 assert(count <=
writeidx -
readidx ||
00385 !
"attempted to unalloc() more than unallocable()");
00386
writeidx -= count;
00387 }
00388
00389
00390 size_t
WvInPlaceBufStore::unallocable()
const
00391
{
00392
return writeidx -
readidx;
00393 }
00394
00395
00396 void *
WvInPlaceBufStore::mutablepeek(
int offset, size_t count)
00397 {
00398
if (count == 0)
00399
return NULL;
00400 assert(((offset <= 0) ?
00401 size_t(-offset) <=
readidx :
00402 size_t(offset) <
writeidx -
readidx) ||
00403 !
"attempted to peek() with invalid offset or count");
00404
return (
unsigned char*)
data + readidx + offset;
00405 }
00406
00407
00408
00409
00410
00411 WvConstInPlaceBufStore::WvConstInPlaceBufStore(
int _granularity,
00412
const void *_data, size_t _avail) :
00413
WvReadOnlyBufferStoreMixin<
WvBufStore>(_granularity), data(NULL)
00414 {
00415
reset(_data, _avail);
00416 }
00417
00418
00419 void WvConstInPlaceBufStore::reset(
const void *_data, size_t _avail)
00420 {
00421 assert(_data != NULL || _avail == 0);
00422
data = _data;
00423
setavail(_avail);
00424 }
00425
00426
00427 size_t
WvConstInPlaceBufStore::used()
const
00428
{
00429
return avail -
readidx;
00430 }
00431
00432
00433 void WvConstInPlaceBufStore::setavail(size_t _avail)
00434 {
00435
avail = _avail;
00436
readidx = 0;
00437 }
00438
00439
00440 const void *
WvConstInPlaceBufStore::get(size_t count)
00441 {
00442 assert(count <=
avail -
readidx ||
00443 !
"attempted to get() more than used()");
00444
const void *
ptr = (
const unsigned char*)
data + readidx;
00445 readidx += count;
00446
return ptr;
00447 }
00448
00449
00450 void WvConstInPlaceBufStore::unget(size_t count)
00451 {
00452 assert(count <=
readidx ||
00453 !
"attempted to unget() more than ungettable()");
00454 readidx -= count;
00455 }
00456
00457
00458 size_t
WvConstInPlaceBufStore::ungettable()
const
00459
{
00460
return readidx;
00461 }
00462
00463
00464 const void *
WvConstInPlaceBufStore::peek(
int offset, size_t count)
00465 {
00466
if (count == 0)
00467
return NULL;
00468 assert(((offset <= 0) ?
00469 size_t(-offset) <=
readidx :
00470 size_t(offset) <
avail -
readidx) ||
00471 !
"attempted to peek() with invalid offset or count");
00472
return (
const unsigned char*)
data + readidx + offset;
00473 }
00474
00475
00476 void WvConstInPlaceBufStore::zap()
00477 {
00478
readidx =
avail = 0;
00479 }
00480
00481
00482
00483
00484
00485 WvCircularBufStore::WvCircularBufStore(
int _granularity,
00486
void *_data, size_t _avail, size_t _size,
bool _autofree) :
00487
WvBufStore(_granularity), data(NULL)
00488 {
00489
reset(_data, _avail, _size, _autofree);
00490 }
00491
00492
00493 WvCircularBufStore::WvCircularBufStore(
int _granularity, size_t _size) :
00494
WvBufStore(_granularity), data(NULL)
00495 {
00496
reset(
memops.newarray(_size), 0, _size,
true);
00497 }
00498
00499
00500 WvCircularBufStore::~WvCircularBufStore()
00501 {
00502
if (
data &&
xautofree)
00503
memops.deletearray(
data);
00504 }
00505
00506
00507 void WvCircularBufStore::reset(
void *_data, size_t _avail,
00508 size_t _size,
bool _autofree =
false)
00509 {
00510 assert(_data != NULL || _avail == 0);
00511
if (
data && _data !=
data &&
xautofree)
00512
memops.deletearray(
data);
00513
data = _data;
00514
xautofree = _autofree;
00515
xsize = _size;
00516
setavail(_avail);
00517 }
00518
00519
00520 void WvCircularBufStore::setavail(size_t _avail)
00521 {
00522 assert(_avail <=
xsize);
00523
head = 0;
00524
totalused =
totalinit = _avail;
00525 }
00526
00527
00528 size_t
WvCircularBufStore::used()
const
00529
{
00530
return totalused;
00531 }
00532
00533
00534 size_t
WvCircularBufStore::optgettable()
const
00535
{
00536 size_t avail =
xsize -
head;
00537
if (avail >
totalused)
00538 avail =
totalused;
00539
return avail;
00540 }
00541
00542
00543 const void *
WvCircularBufStore::get(size_t count)
00544 {
00545 assert(count <=
totalused ||
00546 !
"attempted to get() more than used()");
00547 size_t first =
ensurecontiguous(0, count,
false );
00548
const void *tmpptr = (
const unsigned char*)
data + first;
00549
head = (
head + count) %
xsize;
00550 totalused -= count;
00551
return tmpptr;
00552 }
00553
00554
00555 void WvCircularBufStore::unget(size_t count)
00556 {
00557 assert(count <=
totalinit -
totalused ||
00558 !
"attempted to unget() more than ungettable()");
00559
head = (
head +
xsize - count) %
xsize;
00560 totalused += count;
00561 }
00562
00563
00564 size_t
WvCircularBufStore::ungettable()
const
00565
{
00566
return totalinit -
totalused;
00567 }
00568
00569
00570 void WvCircularBufStore::zap()
00571 {
00572
head = 0;
00573
totalused =
totalinit = 0;
00574 }
00575
00576
00577 size_t
WvCircularBufStore::free()
const
00578
{
00579
return xsize -
totalused;
00580 }
00581
00582
00583 size_t
WvCircularBufStore::optallocable()
const
00584
{
00585 size_t tail =
head +
totalused;
00586
if (tail >=
xsize)
00587
return xsize - totalused;
00588
return xsize - tail;
00589 }
00590
00591
00592 void *
WvCircularBufStore::alloc(size_t count)
00593 {
00594 assert(count <=
xsize -
totalused ||
00595 !
"attempted to alloc() more than free()");
00596
totalinit = totalused;
00597 size_t first =
ensurecontiguous(totalused, count,
00598
false );
00599
void *tmpptr = (
unsigned char*)
data + first;
00600 totalused += count;
00601
totalinit += count;
00602
return tmpptr;
00603 }
00604
00605
00606 void WvCircularBufStore::unalloc(size_t count)
00607 {
00608 assert(count <=
totalused ||
00609 !
"attempted to unalloc() more than unallocable()");
00610 totalused -= count;
00611
totalinit -= count;
00612 }
00613
00614
00615 size_t
WvCircularBufStore::unallocable()
const
00616
{
00617
return totalused;
00618 }
00619
00620
00621 void *
WvCircularBufStore::mutablepeek(
int offset, size_t count)
00622 {
00623
if (count == 0)
00624
return NULL;
00625 assert(((offset <= 0) ?
00626 size_t(-offset) <=
totalinit -
totalused :
00627 size_t(offset) <
totalused) ||
00628 !
"attempted to peek() with invalid offset or count");
00629 size_t first =
ensurecontiguous(offset, count,
00630
true );
00631
void *tmpptr = (
unsigned char*)
data + first;
00632
return tmpptr;
00633 }
00634
00635
00636 void WvCircularBufStore::normalize()
00637 {
00638
00639
totalinit =
totalused;
00640
00641
00642
compact(
data,
xsize,
head, totalused);
00643
head = 0;
00644 }
00645
00646
00647 size_t
WvCircularBufStore::ensurecontiguous(
int offset,
00648 size_t count,
bool keephistory)
00649 {
00650
00651 size_t start = (
head + offset +
xsize) %
xsize;
00652
if (count != 0)
00653 {
00654 size_t end = start + count;
00655
if (end >
xsize)
00656 {
00657
00658
00659 size_t keepstart =
head;
00660
if (keephistory)
00661 {
00662
00663 keepstart +=
totalused -
totalinit +
xsize;
00664 }
00665
else
00666 {
00667
00668
totalinit =
totalused;
00669 }
00670 keepstart %=
xsize;
00671
00672
00673
compact(
data,
xsize, keepstart,
totalinit);
00674 head =
totalinit -
totalused;
00675
00676
00677 start = (head + offset +
xsize) %
xsize;
00678 }
00679 }
00680
return start;
00681 }
00682
00683
00684 void WvCircularBufStore::compact(
void *data, size_t size,
00685 size_t head, size_t count)
00686 {
00687
if (count == 0)
00688 {
00689
00690
00691
return;
00692 }
00693
00694
if (head + count <= size)
00695 {
00696
00697
00698
memops.uninit_move(data, (
unsigned char*)data + head, count);
00699
return;
00700 }
00701
00702 size_t headcount = size - head;
00703 size_t tailcount = count - headcount;
00704 size_t freecount = size - count;
00705
if (freecount >= headcount)
00706 {
00707
00708
00709
memops.uninit_move((
unsigned char*)data + headcount,
00710 data, tailcount);
00711
memops.uninit_move(data, (
unsigned char*)data + head,
00712 headcount);
00713
return;
00714 }
00715
00716
00717
00718
unsigned char *start = (
unsigned char*)data;
00719
unsigned char *end = (
unsigned char*)data + head;
00720
while (tailcount >= headcount)
00721 {
00722
memops.swap(start, end, headcount);
00723 start += headcount;
00724 tailcount -= headcount;
00725 }
00726
00727
00728
void *buf =
memops.newarray(tailcount);
00729
memops.uninit_move(buf, start, tailcount);
00730
memops.uninit_move(start, end, headcount);
00731
memops.uninit_move(start + headcount, buf, tailcount);
00732
memops.deletearray(buf);
00733 }
00734
00735
00736
00737
00738
00739 WvLinkedBufferStore::WvLinkedBufferStore(
int _granularity) :
00740
WvBufStore(_granularity), totalused(0), maxungettable(0)
00741 {
00742 }
00743
00744
00745 bool WvLinkedBufferStore::usessubbuffers()
const
00746
{
00747
return true;
00748 }
00749
00750
00751 size_t
WvLinkedBufferStore::numsubbuffers()
const
00752
{
00753
return list.count();
00754 }
00755
00756
00757 WvBufStore *
WvLinkedBufferStore::firstsubbuffer()
const
00758
{
00759
return list.first();
00760 }
00761
00762
00763 void WvLinkedBufferStore::appendsubbuffer(
WvBufStore *buffer,
00764
bool autofree)
00765 {
00766
list.append(buffer, autofree);
00767
totalused += buffer->
used();
00768 }
00769
00770
00771 void WvLinkedBufferStore::prependsubbuffer(
WvBufStore *buffer,
00772
bool autofree)
00773 {
00774
list.prepend(buffer, autofree);
00775
totalused += buffer->
used();
00776
maxungettable = 0;
00777 }
00778
00779
00780 bool WvLinkedBufferStore::unlinksubbuffer(
WvBufStore *buffer,
00781
bool allowautofree)
00782 {
00783 WvBufStoreList::Iter it(
list);
00784
WvLink *link = it.find(buffer);
00785 assert(link);
00786
00787
bool autofree = it.link->auto_free;
00788
totalused -= buffer->
used();
00789
if (buffer ==
list.first())
00790
maxungettable = 0;
00791
if (! allowautofree)
00792 it.link->auto_free =
false;
00793 it.unlink();
00794
return autofree;
00795 }
00796
00797
00798 size_t
WvLinkedBufferStore::used()
const
00799
{
00800 assert(!
totalused || !
list.isempty());
00801
return totalused;
00802 }
00803
00804
00805 size_t
WvLinkedBufferStore::optgettable()
const
00806
{
00807
00808 size_t count;
00809 WvBufStoreList::Iter it(
list);
00810
for (it.rewind(); it.next(); )
00811
if ((count = it->optgettable()) != 0)
00812
return count;
00813
return 0;
00814 }
00815
00816
00817 const void *
WvLinkedBufferStore::get(size_t count)
00818 {
00819 assert(!
totalused || !
list.isempty());
00820
if (count == 0)
00821
return NULL;
00822
00823 assert(count <=
totalused);
00824 assert(count > 0);
00825
00826 totalused -= count;
00827
00828 assert(totalused >= 0);
00829
00830
00831
WvBufStore *buf;
00832 size_t availused;
00833 WvBufStoreList::Iter it(
list);
00834
for (;;)
00835 {
00836 it.rewind(); it.next();
00837 buf = it.ptr();
00838 assert(buf &&
"attempted to get() more than used()" &&
00839
"totalused is wrong!");
00840
00841 availused = buf->
used();
00842
if (availused != 0)
00843
break;
00844
00845
00846 do_xunlink(it);
00847 }
00848
00849
00850
if (availused < count)
00851 buf =
coalesce(it, count);
00852
00853
maxungettable += count;
00854
return buf->
get(count);
00855 }
00856
00857
00858 void WvLinkedBufferStore::unget(size_t count)
00859 {
00860 assert(!
totalused || !
list.isempty());
00861
if (count == 0)
00862
return;
00863 assert(count > 0);
00864 assert(!
list.isempty());
00865 assert(count <=
maxungettable);
00866
totalused += count;
00867 maxungettable -= count;
00868
list.first()->unget(count);
00869 }
00870
00871
00872 size_t
WvLinkedBufferStore::ungettable()
const
00873
{
00874 assert(!
totalused || !
list.isempty());
00875
if (
list.isempty())
00876 {
00877 assert(
maxungettable == 0);
00878
return 0;
00879 }
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889 size_t avail =
list.first()->ungettable();
00890
if (avail >
maxungettable)
00891 avail =
maxungettable;
00892
return avail;
00893 }
00894
00895
00896 void WvLinkedBufferStore::zap()
00897 {
00898
totalused = 0;
00899
maxungettable = 0;
00900 WvBufStoreList::Iter it(
list);
00901
for (it.rewind(); it.next(); )
00902 do_xunlink(it);
00903 }
00904
00905
00906 size_t
WvLinkedBufferStore::free()
const
00907
{
00908
if (!
list.isempty())
00909
return list.last()->free();
00910
return 0;
00911 }
00912
00913
00914 size_t
WvLinkedBufferStore::optallocable()
const
00915
{
00916
if (!
list.isempty())
00917
return list.last()->optallocable();
00918
return 0;
00919 }
00920
00921
00922 void *
WvLinkedBufferStore::alloc(size_t count)
00923 {
00924
if (count == 0)
00925
return NULL;
00926 assert(!
list.isempty() &&
"attempted to alloc() more than free()");
00927
totalused += count;
00928
return list.last()->alloc(count);
00929 }
00930
00931
00932 void WvLinkedBufferStore::unalloc(size_t count)
00933 {
00934 assert(count <=
totalused);
00935
00936 totalused -= count;
00937
while (count > 0)
00938 {
00939 assert(!
list.isempty() &&
00940
"attempted to unalloc() more than unallocable()" &&
00941
"totalused is wrong");
00942
WvBufStore *buf =
list.last();
00943 size_t avail = buf->
unallocable();
00944
if (count < avail)
00945 {
00946 buf->
unalloc(count);
00947
break;
00948 }
00949
00950 WvBufStoreList::Iter it(
list);
00951 it.find(buf);
00952 do_xunlink(it);
00953
00954 count -= avail;
00955 }
00956 }
00957
00958
00959 size_t
WvLinkedBufferStore::unallocable()
const
00960
{
00961
return totalused;
00962 }
00963
00964
00965 size_t
WvLinkedBufferStore::optpeekable(
int offset)
const
00966
{
00967
00968 WvBufStoreList::Iter it(
list);
00969 offset =
search(it, offset);
00970
WvBufStore *buf = it.ptr();
00971
if (!buf)
00972
return 0;
00973
return buf->
optpeekable(offset);
00974 }
00975
00976
00977 void *
WvLinkedBufferStore::mutablepeek(
int offset, size_t count)
00978 {
00979
if (count == 0)
00980
return NULL;
00981
00982
00983 WvBufStoreList::Iter it(
list);
00984 offset =
search(it, offset);
00985
WvBufStore *buf = it.ptr();
00986 assert(buf &&
"attempted to peek() with invalid offset or count");
00987
00988
00989 size_t availpeek = buf->
peekable(offset);
00990
if (availpeek < count)
00991 buf =
coalesce(it, count);
00992
return buf->
mutablepeek(offset, count);
00993 }
00994
00995
00996 WvBufStore *
WvLinkedBufferStore::newbuffer(size_t minsize)
00997 {
00998 minsize =
roundup(minsize, granularity);
00999
01000
return new WvCircularBufStore(granularity, minsize);
01001 }
01002
01003
01004 void WvLinkedBufferStore::recyclebuffer(
WvBufStore *buffer)
01005 {
01006
delete buffer;
01007 }
01008
01009
01010 int WvLinkedBufferStore::search(WvBufStoreList::Iter &it,
01011
int offset)
const
01012
{
01013 it.rewind();
01014
if (it.next())
01015 {
01016
if (offset < 0)
01017 {
01018
01019
WvBufStore *buf = it.ptr();
01020
if (size_t(-offset) <= buf->
ungettable())
01021
return offset;
01022 it.rewind();
01023 }
01024
else
01025 {
01026
01027
do
01028 {
01029
WvBufStore *buf = it.ptr();
01030 size_t avail = buf->
used();
01031
if (size_t(offset) < avail)
01032
return offset;
01033 offset -= avail;
01034 }
01035
while (it.next());
01036 }
01037 }
01038
return 0;
01039 }
01040
01041
01042 WvBufStore *
WvLinkedBufferStore::coalesce(WvBufStoreList::Iter &it,
01043 size_t count)
01044 {
01045
WvBufStore *buf = it.ptr();
01046 size_t availused = buf->
used();
01047
if (count <= availused)
01048
return buf;
01049
01050
01051 size_t needed = count - availused;
01052 size_t availfree = buf->
free();
01053
if (availfree < needed)
01054 {
01055
01056
01057
01058 size_t mustskip = 0;
01059
if (buf ==
list.first() &&
totalused != 0)
01060 {
01061
01062
01063
01064 mustskip =
ungettable();
01065 buf->
unget(mustskip);
01066 }
01067
01068 needed = count + mustskip;
01069 buf =
newbuffer(needed);
01070
01071
01072
if (mustskip != 0)
01073 {
01074 buf->
alloc(mustskip);
01075 buf->
skip(mustskip);
01076 assert(buf->
ungettable() >= mustskip);
01077 }
01078
01079
01080
list.add_after(it.prev, buf,
true);
01081 it.find(buf);
01082 }
01083
01084
01085
while (it.next())
01086 {
01087
WvBufStore *itbuf = it.ptr();
01088 size_t chunk = itbuf->
used();
01089
if (chunk > 0)
01090 {
01091
if (chunk > needed)
01092 chunk = needed;
01093 buf->
merge(*itbuf, chunk);
01094 needed -= chunk;
01095
if (needed == 0)
01096
return buf;
01097 }
01098 do_xunlink(it);
01099 }
01100 assert(
false &&
"invalid count during get() or peek()");
01101
return NULL;
01102 }
01103
01104
01105
void WvLinkedBufferStore::do_xunlink(WvBufStoreList::Iter &it)
01106 {
01107
WvBufStore *buf = it.ptr();
01108
if (buf == list.first())
01109 maxungettable = 0;
01110
01111
bool autofree = it.link->auto_free;
01112 it.link->auto_free =
false;
01113 it.xunlink();
01114
if (autofree)
01115 recyclebuffer(buf);
01116 }
01117
01118
01119
01120
01121
01122 WvDynBufStore::WvDynBufStore(size_t _granularity,
01123 size_t _minalloc, size_t _maxalloc) :
01124
WvLinkedBufferStore(_granularity),
01125 minalloc(_minalloc), maxalloc(_maxalloc)
01126 {
01127 assert(maxalloc >= minalloc);
01128 }
01129
01130
01131 size_t
WvDynBufStore::free()
const
01132
{
01133
return UNLIMITED_FREE_SPACE;
01134 }
01135
01136
01137 size_t
WvDynBufStore::optallocable()
const
01138
{
01139 size_t avail =
WvLinkedBufferStore::optallocable();
01140
if (avail == 0)
01141 avail =
UNLIMITED_FREE_SPACE;
01142
return avail;
01143 }
01144
01145
01146 void *
WvDynBufStore::alloc(size_t count)
01147 {
01148
if (count >
WvLinkedBufferStore::free())
01149 {
01150
WvBufStore *buf =
newbuffer(count);
01151 appendsubbuffer(buf,
true);
01152 }
01153
return WvLinkedBufferStore::alloc(count);
01154 }
01155
01156
01157 WvBufStore *
WvDynBufStore::newbuffer(size_t minsize)
01158 {
01159
01160
01161
01162 size_t size =
used();
01163
if (size < minsize * 2)
01164 size = minsize * 2;
01165
if (size < minalloc)
01166 size = minalloc;
01167
else if (size > maxalloc)
01168 size = maxalloc;
01169
if (size < minsize)
01170 size = minsize;
01171
return WvLinkedBufferStore::newbuffer(size);
01172 }
01173
01174
01175
01176
01177
01178 WvNullBufStore::WvNullBufStore(size_t _granularity) :
01179
WvWriteOnlyBufferStoreMixin<
01180
WvReadOnlyBufferStoreMixin<
WvBufStore> >(_granularity)
01181 {
01182 }
01183
01184
01185
01186
01187
01188 WvBufCursorStore::WvBufCursorStore(size_t _granularity,
01189
WvBufStore *_buf,
int _start, size_t _length) :
01190
WvReadOnlyBufferStoreMixin<
WvBufStore>(_granularity),
01191 buf(_buf), start(_start), length(_length), shift(0)
01192 {
01193 }
01194
01195
01196 bool WvBufCursorStore::isreadable()
const
01197
{
01198
return buf->
isreadable();
01199 }
01200
01201
01202 size_t
WvBufCursorStore::used()
const
01203
{
01204
return length -
shift;
01205 }
01206
01207
01208 size_t
WvBufCursorStore::optgettable()
const
01209
{
01210 size_t avail =
buf->
optpeekable(
start +
shift);
01211 assert(avail != 0 ||
length == shift ||
01212 !
"buffer cursor operating over invalid region");
01213
if (avail >
length)
01214 avail =
length;
01215
return avail;
01216 }
01217
01218
01219 const void *
WvBufCursorStore::get(size_t count)
01220 {
01221 assert(count <=
length -
shift ||
01222 !
"attempted to get() more than used()");
01223
const void *data =
buf->
peek(
start + shift, count);
01224 shift += count;
01225
return data;
01226 }
01227
01228
01229 void WvBufCursorStore::skip(size_t count)
01230 {
01231 assert(count <=
length -
shift ||
01232 !
"attempted to skip() more than used()");
01233 shift += count;
01234 }
01235
01236
01237 void WvBufCursorStore::unget(size_t count)
01238 {
01239 assert(count <=
shift ||
01240 !
"attempted to unget() more than ungettable()");
01241 shift -= count;
01242 }
01243
01244
01245 size_t
WvBufCursorStore::ungettable()
const
01246
{
01247
return shift;
01248 }
01249
01250
01251 void WvBufCursorStore::zap()
01252 {
01253
shift =
length;
01254 }
01255
01256
01257 size_t
WvBufCursorStore::peekable(
int offset)
const
01258
{
01259 offset +=
shift;
01260 offset -=
start;
01261
if (offset < 0 || offset > int(
length))
01262
return 0;
01263
return length - size_t(offset);
01264 }
01265
01266
01267 size_t
WvBufCursorStore::optpeekable(
int offset)
const
01268
{
01269 size_t avail =
buf->
optpeekable(
start +
shift + offset);
01270 assert(avail != 0 ||
length ==
shift ||
01271 !
"buffer cursor operating over invalid region");
01272 size_t max =
peekable(offset);
01273
if (avail > max)
01274 avail = max;
01275
return avail;
01276 }
01277
01278
01279 const void *
WvBufCursorStore::peek(
int offset, size_t count)
01280 {
01281 offset +=
shift;
01282 assert((offset >=
start && offset -
start + count <=
length) ||
01283 !
"attempted to peek() with invalid offset or count");
01284
return buf->
peek(offset, count);
01285 }
01286
01287
01288 bool WvBufCursorStore::iswritable()
const
01289
{
01290
01291
return buf->
iswritable();
01292 }
01293
01294
01295 void *
WvBufCursorStore::mutablepeek(
int offset, size_t count)
01296 {
01297 offset +=
shift;
01298 assert((offset >=
start && offset -
start + count <=
length) ||
01299 !
"attempted to peek() with invalid offset or count");
01300
return buf->
mutablepeek(offset, count);
01301 }