2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
5 * Defines basic buffer storage classes.
6 * These are not intended for use directly by clients.
7 * See "wvbufbase.h" for the public API.
9 #include "wvbufstore.h"
11 #include <sys/types.h>
14 * An abstraction for memory transfer operations.
16 * This is in preparation for supporting buffers of full-blown
17 * objects that have special copy and destruction semantics,
22 /** Copies initialized region to uninitialized region. */
23 inline void uninit_copy(void *target
, const void *source
,
26 memcpy(target
, source
, count
);
28 /** Copies initialized region to initialized region. */
29 inline void copy(void *target
, const void *source
, size_t count
)
31 uninit(target
, count
);
32 memcpy(target
, source
, count
);
35 * Moves initialized region to uninitialized region.
36 * Source data becomes uninitialized.
38 inline void uninit_move(void *target
, void *source
,
41 memmove(target
, source
, count
);
42 uninit(source
, count
);
44 /** Swaps initialized regions. */
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
;
57 /** Uninitializes a region. */
58 inline void uninit(void *target
, size_t count
)
61 /** Creates a new array. */
62 inline void *newarray(size_t count
)
64 return new unsigned char[count
];
66 /** Deletes an uninitialized array. */
67 inline void deletearray(void *buf
)
69 deletev (unsigned char*)buf
;
73 /** Rounds the value up to the specified boundary. */
74 inline size_t roundup(size_t value
, size_t boundary
)
76 size_t mod
= value
% boundary
;
77 return mod
? value
+ boundary
- mod
: value
;
82 /***** WvBufStore *****/
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
;
107 return 0; // out-of-bounds
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
);
121 memops
.uninit_copy(buf
, data
, 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
);
138 memops
.uninit_copy(buf
, data
, 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
);
156 memops
.uninit_copy(buf
, data
, amount
);
157 data
= (const unsigned char*)data
+ amount
;
163 void WvBufStore::fastput(const void *data
, size_t count
)
165 void *buf
= alloc(count
);
166 memops
.uninit_copy(buf
, data
, 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
)
203 if (usessubbuffers() && instore
.usessubbuffers())
205 // merge quickly by stealing subbuffers from the other buffer
208 WvBufStore
*buf
= instore
.firstsubbuffer();
212 size_t avail
= buf
->used();
216 // move the entire buffer
217 bool autofree
= instore
.unlinksubbuffer(buf
, false);
218 appendsubbuffer(buf
, autofree
);
224 // merge slowly by copying data
225 basicmerge(instore
, count
);
229 void WvBufStore::basicmerge(WvBufStore
&instore
, size_t count
)
231 // move bytes as efficiently as we can using only the public API
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
)
260 memops
.uninit_copy(outdata
, indata
, inavail
);
268 outdata
= (unsigned char*)outdata
+ inavail
;
273 memops
.uninit_copy(outdata
, indata
, outavail
);
275 if (count
== 0) return;
277 indata
= (const unsigned char*)indata
+ outavail
;
285 /***** WvInPlaceBufStore *****/
287 WvInPlaceBufStore::WvInPlaceBufStore(int _granularity
,
288 void *_data
, size_t _avail
, size_t _size
, bool _autofree
) :
289 WvBufStore(_granularity
), data(NULL
)
291 reset(_data
, _avail
, _size
, _autofree
);
295 WvInPlaceBufStore::WvInPlaceBufStore(int _granularity
, size_t _size
) :
296 WvBufStore(_granularity
), data(NULL
)
298 reset(memops
.newarray(_size
), 0, _size
, true);
302 WvInPlaceBufStore::~WvInPlaceBufStore()
304 if (data
&& xautofree
)
305 memops
.deletearray(data
);
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
)
314 memops
.deletearray(data
);
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
;
409 /***** WvConstInPlaceBufStore *****/
411 WvConstInPlaceBufStore::WvConstInPlaceBufStore(int _granularity
,
412 const void *_data
, size_t _avail
) :
413 WvReadOnlyBufferStoreMixin
<WvBufStore
>(_granularity
), data(NULL
)
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()
483 /***** WvCircularBufStore *****/
485 WvCircularBufStore::WvCircularBufStore(int _granularity
,
486 void *_data
, size_t _avail
, size_t _size
, bool _autofree
) :
487 WvBufStore(_granularity
), data(NULL
)
489 reset(_data
, _avail
, _size
, _autofree
);
493 WvCircularBufStore::WvCircularBufStore(int _granularity
, size_t _size
) :
494 WvBufStore(_granularity
), data(NULL
)
496 reset(memops
.newarray(_size
), 0, _size
, true);
500 WvCircularBufStore::~WvCircularBufStore()
502 if (data
&& xautofree
)
503 memops
.deletearray(data
);
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
)
512 memops
.deletearray(data
);
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()");
547 size_t first
= ensurecontiguous(0, count
, false /*keephistory*/);
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
; // always discard history
597 size_t first
= ensurecontiguous(totalused
, count
,
598 false /*keephistory*/);
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");
629 size_t first
= ensurecontiguous(offset
, count
,
630 true /*keephistory*/);
631 void *tmpptr
= (unsigned char*)data
+ first
;
636 void WvCircularBufStore::normalize()
638 // discard history to minimize data transfers
639 totalinit
= totalused
;
641 // normalize the buffer
642 compact(data
, xsize
, head
, totalused
);
647 size_t WvCircularBufStore::ensurecontiguous(int offset
,
648 size_t count
, bool keephistory
)
650 // determine the region of interest
651 size_t start
= (head
+ offset
+ xsize
) % xsize
;
654 size_t end
= start
+ count
;
657 // the region is not entirely contiguous
658 // determine the region that must be normalized
659 size_t keepstart
= head
;
662 // adjust the region to include history
663 keepstart
+= totalused
- totalinit
+ xsize
;
667 // discard history to minimize data transfers
668 totalinit
= totalused
;
672 // normalize the buffer over this region
673 compact(data
, xsize
, keepstart
, totalinit
);
674 head
= totalinit
- totalused
;
676 // compute the new start offset
677 start
= (head
+ offset
+ xsize
) % xsize
;
684 void WvCircularBufStore::compact(void *data
, size_t size
,
685 size_t head
, size_t count
)
689 // Case 1: Empty region
694 if (head
+ count
<= size
)
696 // Case 2: Contiguous region
697 // Requires count moves
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
)
707 // Case 3: Non-contiguous region, does not require swapping
708 // Requires count moves
709 memops
.uninit_move((unsigned char*)data
+ headcount
,
711 memops
.uninit_move(data
, (unsigned char*)data
+ head
,
716 // Case 4: Non-contiguous region, requires swapping
717 // Requires count * 2 moves
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
;
726 // Now the array looks like: |a|b|c|g|h|_|d|e|f|
727 // FIXME: this is an interim solution
728 void *buf
= memops
.newarray(tailcount
);
729 memops
.uninit_move(buf
, start
, tailcount
);
730 memops
.uninit_move(start
, end
, headcount
);
731 memops
.uninit_move(start
+ headcount
, buf
, tailcount
);
732 memops
.deletearray(buf
);
737 /***** WvLinkedBufferStore *****/
739 WvLinkedBufferStore::WvLinkedBufferStore(int _granularity
) :
740 WvBufStore(_granularity
), totalused(0), maxungettable(0)
745 bool WvLinkedBufferStore::usessubbuffers() const
751 size_t WvLinkedBufferStore::numsubbuffers() const
757 WvBufStore
*WvLinkedBufferStore::firstsubbuffer() const
763 void WvLinkedBufferStore::appendsubbuffer(WvBufStore
*buffer
,
766 list
.append(buffer
, autofree
);
767 totalused
+= buffer
->used();
771 void WvLinkedBufferStore::prependsubbuffer(WvBufStore
*buffer
,
774 list
.prepend(buffer
, autofree
);
775 totalused
+= buffer
->used();
780 bool WvLinkedBufferStore::unlinksubbuffer(WvBufStore
*buffer
,
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);
793 it
.unlink(); // do not recycle the buffer
798 size_t WvLinkedBufferStore::used() const
800 assert(!totalused
|| !list
.isempty());
805 size_t WvLinkedBufferStore::optgettable() const
807 // find the first buffer with an optgettable() and return that
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);
830 // search for first non-empty buffer
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();
845 // unlink the leading empty buffer
850 if (availused
< count
)
851 buf
= coalesce(it
, 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);
881 // maxungettable and list.first()->ungettable() can get out of sync in two ways:
882 // - coalescing moves data from later buffers to the first one, which
883 // leaves it as ungettable in those buffers. So when we first start to
884 // use a buffer, its ungettable() count may be too high. (This is the
885 // reason maxungettable exists.)
886 // - some calls (ie. alloc) may clear all ungettable data from the first
887 // buffer without telling us. So there might be less data to unget than we
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");
942 WvBufStore
*buf
= list
.last();
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
967 // search for the buffer that contains the offset
968 WvBufStoreList::Iter
it(list
);
969 int newoffset
= search(it
, offset
);
970 WvBufStore
*buf
= it
.ptr();
972 return 0; // out of bounds
973 return buf
->optpeekable(newoffset
);
977 void *WvLinkedBufferStore::mutablepeek(int offset
, size_t count
)
982 // search for the buffer that contains the offset
983 WvBufStoreList::Iter
it(list
);
984 offset
= search(it
, offset
);
985 WvBufStore
*buf
= it
.ptr();
986 assert(buf
&& "attempted to peek() with invalid offset or count");
988 // return data if we have enough
989 size_t availpeek
= buf
->peekable(offset
);
990 if (availpeek
< count
)
991 buf
= coalesce(it
, count
);
992 return buf
->mutablepeek(offset
, count
);
996 WvBufStore
*WvLinkedBufferStore::newbuffer(size_t minsize
)
998 minsize
= roundup(minsize
, granularity
);
999 //return new WvInPlaceBufStore(granularity, minsize);
1000 return new WvCircularBufStore(granularity
, minsize
);
1004 void WvLinkedBufferStore::recyclebuffer(WvBufStore
*buffer
)
1010 int WvLinkedBufferStore::search(WvBufStoreList::Iter
&it
,
1018 // inside unget() region
1019 WvBufStore
*buf
= it
.ptr();
1020 if (size_t(-offset
) <= buf
->ungettable())
1022 it
.rewind(); // mark out of bounds
1026 // inside get() region
1029 WvBufStore
*buf
= it
.ptr();
1030 size_t avail
= buf
->used();
1031 if (size_t(offset
) < avail
)
1042 WvBufStore
*WvLinkedBufferStore::coalesce(WvBufStoreList::Iter
&it
,
1045 WvBufStore
*buf
= it
.ptr();
1046 size_t availused
= buf
->used();
1047 if (count
<= availused
)
1050 // allocate a new buffer if there is not enough room to coalesce
1051 size_t needed
= count
- availused
;
1052 size_t availfree
= buf
->free();
1053 size_t mustskip
= 0;
1054 if (availfree
< needed
)
1056 // if this is the first buffer, then we need to unget as
1057 // much as possible to ensure it does not get discarded
1058 // during the coalescing phase
1059 if (buf
== list
.first() && totalused
!= 0)
1061 // use ungettable() instead of buf->ungettable() because we might
1062 // have reset it to 0
1063 // FIXME: uh... who might have reset it to 0, and why?
1064 mustskip
= ungettable();
1065 buf
->unget(mustskip
);
1068 needed
= count
+ mustskip
;
1069 buf
= newbuffer(needed
);
1071 // insert the buffer before the previous link
1072 list
.add_after(it
.prev
, buf
, true);
1076 // coalesce subsequent buffers into the first
1079 WvBufStore
*itbuf
= it
.ptr();
1080 size_t chunk
= itbuf
->used();
1085 buf
->merge(*itbuf
, chunk
);
1089 buf
->skip(mustskip
);
1093 do_xunlink(it
); // buffer is now empty
1095 assert(false && "invalid count during get() or peek()");
1100 void WvLinkedBufferStore::do_xunlink(WvBufStoreList::Iter
&it
)
1102 WvBufStore
*buf
= it
.ptr();
1103 if (buf
== list
.first())
1106 bool autofree
= it
.get_autofree();
1107 it
.set_autofree(false);
1115 /***** WvDynBufStore *****/
1117 WvDynBufStore::WvDynBufStore(size_t _granularity
,
1118 size_t _minalloc
, size_t _maxalloc
) :
1119 WvLinkedBufferStore(_granularity
),
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())
1145 WvBufStore
*buf
= newbuffer(count
);
1146 appendsubbuffer(buf
, true);
1148 return WvLinkedBufferStore::alloc(count
);
1152 WvBufStore
*WvDynBufStore::newbuffer(size_t minsize
)
1154 // allocate a new buffer
1155 // try to approximate exponential growth by at least doubling
1156 // the amount of space available for immediate use
1157 size_t size
= used();
1158 if (size
< minsize
* 2)
1160 if (size
< minalloc
)
1162 else if (size
> maxalloc
)
1166 return WvLinkedBufferStore::newbuffer(size
);
1171 /***** WvNullBufStore *****/
1173 WvNullBufStore::WvNullBufStore(size_t _granularity
) :
1174 WvWriteOnlyBufferStoreMixin
<
1175 WvReadOnlyBufferStoreMixin
<WvBufStore
> >(_granularity
)
1181 /***** WvBufCursorStore *****/
1183 WvBufCursorStore::WvBufCursorStore(size_t _granularity
,
1184 WvBufStore
*_buf
, int _start
, size_t _length
) :
1185 WvReadOnlyBufferStoreMixin
<WvBufStore
>(_granularity
),
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
1285 // check if mutablepeek() is supported
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
);