2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
5 * A generic buffering API.
6 * Please declare specializations in a separate header file,
9 #ifndef __WVBUFFERBASE_H
10 #define __WVBUFFERBASE_H
12 #include "wvbufstore.h"
18 * An abstract generic buffer template.
19 * Buffers are simple data queues designed to ease the construction of
20 * functions that must generate, consume, or transform large amount of
21 * data in pipeline fashion. Concrete buffer subclases define the actual
22 * storage mechanism and queuing machinery. In addition they may provide
23 * additional functionality for accomplishing particular tasks.
25 * The base component is split into two parts, WvBufBaseCommonImpl
26 * that defines the common API for all buffer types, and WvBufBase
27 * that allows specializations to be defined to add functionality
28 * to the base type. When passing around buffer objects, you should
29 * use the WvBufBase<T> type rather than WvBufBaseCommonImpl<T>.
32 * "T" is the type of object to store, must be a primitive or a struct
33 * without special initialization, copy, or assignment semantics
36 class WvBufBaseCommonImpl
40 typedef WvBufBase
<T
> Buffer
;
45 explicit WvBufBaseCommonImpl(
46 const WvBufBaseCommonImpl
&other
) { }
50 * Initializes the buffer.
52 * Note: Does not take ownership of the storage object.
55 * "store" is the low-level storage object
57 explicit WvBufBaseCommonImpl(WvBufStore
*store
) :
61 /** Destroys the buffer. */
62 virtual ~WvBufBaseCommonImpl() { }
65 * Returns a pointer to the underlying storage class object.
67 * Returns: the low-level storage class object pointer, non-null
69 WvBufStore
*getstore()
74 /*** Buffer Reading ***/
77 * Returns true if the buffer supports reading.
79 * Returns: true if reading is supported
81 bool isreadable() const
83 return store
->isreadable();
87 * Returns the number of elements in the buffer currently
88 * available for reading.
90 * This function could also be called gettable().
94 return store
->used() / sizeof(Elem
);
98 * Reads exactly the specified number of elements and returns
99 * a pointer to a storage location owned by the buffer.
101 * The pointer is only valid until the next non-const buffer
102 * member is called. eg. alloc(size_t)
104 * If count == 0, a NULL pointer may be returned.
106 * It is an error for count to be greater than the number of
107 * available elements in the buffer.
109 * For maximum efficiency, call this function multiple times
110 * with count no greater than optgettable() each time.
112 * After this operation, at least count elements may be ungotten.
114 const T
*get(size_t count
)
119 return static_cast<const T
*>(
120 store
->get(count
* sizeof(Elem
)));
124 * Skips exactly the specified number of elements.
126 * This is equivalent to invoking get(size_t) with the count
127 * and discarding the result, but may be faster for certain
128 * types of buffers. As with get(size_t), the call may be
129 * followed up by an unget(size_t).
131 * It is an error for count to be greater than the number of
132 * available elements in the buffer.
134 * "count" is the number of elements
136 void skip(size_t count
)
138 store
->skip(count
* sizeof(Elem
));
142 * Returns the optimal maximum number of elements in the
143 * buffer currently available for reading without incurring
144 * significant overhead.
148 * - optgettable() <= used()
149 * - optgettable() != 0 if used() != 0
152 * Returns: the number of elements
154 size_t optgettable() const
156 size_t avail
= store
->optgettable();
157 size_t elems
= avail
/ sizeof(Elem
);
158 if (elems
!= 0) return elems
;
159 return avail
!= 0 && store
->used() >= sizeof(Elem
) ? 1 : 0;
163 * Ungets exactly the specified number of elements by returning
164 * them to the buffer for subsequent reads.
166 * This operation may always be safely performed with count
167 * less than or equal to that specified in the last get(size_t)
168 * if no non-const buffer members have been called since then.
170 * If count == 0, nothing happens.
172 * It is an error for count to be greater than ungettable().
175 * "count" is the number of elements
177 void unget(size_t count
)
179 store
->unget(count
* sizeof(Elem
));
183 * Returns the maximum number of elements that may be ungotten
186 * Returns: the number of elements
188 size_t ungettable() const
190 return store
->ungettable() / sizeof(Elem
);
194 * Returns a const pointer into the buffer at the specified
195 * offset to the specified number of elements without actually
196 * adjusting the current get() index.
198 * The pointer is only valid until the next non-const buffer
199 * member is called. eg. alloc(size_t)
201 * If count == 0, a NULL pointer may be returned.
203 * If offset is greater than zero, then elements will be returned
204 * beginning with the with the offset'th element that would be
205 * returned by get(size_t).
207 * If offset equals zero, then elements will be returned beginning
208 * with the next one available for get(size_t).
210 * If offset is less than zero, then elements will be returned
211 * beginning with the first one that would be returned on a
212 * get(size_t) following an unget(-offset).
214 * It is an error for count to be greater than peekable(offset).
216 * For maximum efficiency, call this function multiple times
217 * with count no greater than that returned by optpeekable(size_t)
218 * at incremental offsets.
221 * "offset" is the buffer offset
222 * "count" is the number of elements
223 * Returns: the element storage pointer
225 const T
*peek(int offset
, size_t count
)
227 return static_cast<const T
*>(store
->peek(
228 offset
* sizeof(Elem
), count
* sizeof(Elem
)));
231 size_t peekable(int offset
)
233 return store
->peekable(offset
* sizeof(Elem
)) / sizeof(Elem
);
236 size_t optpeekable(int offset
)
238 offset
*= sizeof(Elem
);
239 size_t avail
= store
->optpeekable(offset
);
240 size_t elems
= avail
/ sizeof(Elem
);
241 if (elems
!= 0) return elems
;
243 store
->peekable(offset
) >= sizeof(Elem
) ? 1 : 0;
249 * For many types of buffers, calling zap() will increased the
250 * amount of free space available for writing (see below) by
251 * an amount greater than used(). Hence it is wise to zap()
252 * a buffer just before writing to it to maximize free space.
254 * After this operation, used() == 0, and often ungettable() == 0.
263 * Reads the next element from the buffer.
265 * It is an error to invoke this method if used() == 0.
267 * After this operation, at least 1 element may be ungotten.
270 * Returns: the element
278 * Returns the element at the specified offset in the buffer.
280 * It is an error to invoke this method if used() == 0.
283 * "offset" is the offset, default 0
284 * Returns: the element
286 T
peek(int offset
= 0)
288 return *peek(offset
* sizeof(Elem
), sizeof(Elem
));
292 * Efficiently copies the specified number of elements from the
293 * buffer to the specified UNINITIALIZED storage location
294 * and removes the elements from the buffer.
296 * It is an error for count to be greater than used().
298 * For maximum efficiency, choose as large a count as possible.
300 * The pointer buf may be NULL only if count == 0.
302 * After this operation, an indeterminate number of elements
306 * "buf" is the buffer that will receive the elements
307 * "count" is the number of elements
309 void move(T
*buf
, size_t count
)
311 store
->move(buf
, count
* sizeof(Elem
));
315 * Efficiently copies the specified number of elements from the
316 * buffer to the specified UNINITIALIZED storage location
317 * but does not remove the elements from the buffer.
319 * It is an error for count to be greater than peekable(offset).
321 * For maximum efficiency, choose as large a count as possible.
323 * The pointer buf may be NULL only if count == 0.
326 * "buf" is the buffer that will receive the elements
327 * "offset" is the buffer offset
328 * "count" is the number of elements
330 void copy(T
*buf
, int offset
, size_t count
)
332 store
->copy(buf
, offset
* sizeof(Elem
), count
* sizeof(Elem
));
335 /*** Buffer Writing ***/
338 * Returns true if the buffer supports writing.
340 * Returns: true if writing is supported
342 bool iswritable() const
348 * Returns the number of elements that the buffer can currently
349 * accept for writing.
351 * Returns: the number of elements
355 return store
->free() / sizeof(Elem
);
359 * Allocates exactly the specified number of elements and returns
360 * a pointer to an UNINITIALIZED storage location owned by the
363 * The pointer is only valid until the next non-const buffer
364 * member is called. eg. alloc(size_t)
366 * If count == 0, a NULL pointer may be returned.
368 * It is an error for count to be greater than free().
370 * For best results, call this function multiple times with
371 * count no greater than optallocable() each time.
373 * After this operation, at least count elements may be unallocated.
376 * "count" is the number of elements
377 * Returns: the element storage pointer
379 T
*alloc(size_t count
)
381 return static_cast<T
*>(store
->alloc(count
* sizeof(Elem
)));
385 * Returns the optimal maximum number of elements that the
386 * buffer can currently accept for writing without incurring
387 * significant overhead.
391 * - optallocable() <= free()
392 * - optallocable() != 0 if free() != 0
395 * Returns: the number of elements
397 size_t optallocable() const
399 size_t avail
= store
->optallocable();
400 size_t elems
= avail
/ sizeof(Elem
);
401 if (elems
!= 0) return elems
;
402 return avail
!= 0 && store
->free() >= sizeof(Elem
) ? 1 : 0;
406 * Unallocates exactly the specified number of elements by removing
407 * them from the buffer and releasing their storage.
409 * This operation may always be safely performed with count
410 * less than or equal to that specified in the last alloc(size_t)
411 * or put(const T*, size_t) if no non-const buffer members have
412 * been called since then.
414 * If count == 0, nothing happens.
416 * It is an error for count to be greater than unallocable().
419 * "count" is the number of elements
421 void unalloc(size_t count
)
423 return store
->unalloc(count
* sizeof(Elem
));
427 * Returns the maximum number of elements that may be unallocated
430 * For all practical purposes, this number will always be at least
431 * as large as the amount currently in use. It is provided
432 * primarily for symmetry, but also to handle cases where
433 * buffer reading (hence used()) is not supported by the
438 * - unallocable() >= used()
441 * Returns: the number of elements
443 size_t unallocable() const
445 return store
->unallocable() / sizeof(Elem
);
449 * Returns a non-const pointer info the buffer at the specified
450 * offset to the specified number of elements without actually
451 * adjusting the current get() index.
453 * Other than the fact that the returned storage is mutable,
454 * operates identically to peek(int, size_t).
457 * "offset" is the buffer offset
458 * "count" is the number of elements
459 * Returns: the element storage pointer
461 T
*mutablepeek(int offset
, size_t count
)
463 return static_cast<T
*>(store
->mutablepeek(
464 offset
* sizeof(Elem
), count
* sizeof(Elem
)));
468 * Writes the specified number of elements from the specified
469 * storage location into the buffer at its tail.
471 * It is an error for count to be greater than free().
473 * For maximum efficiency, choose as large a count as possible.
475 * The pointer buf may be NULL only if count == 0.
477 * After this operation, at least count elements may be unallocated.
480 * "data" is the buffer that contains the elements
481 * "count" is the number of elements
483 void put(const T
*data
, size_t count
)
485 store
->put(data
, count
* sizeof(Elem
));
489 * Efficiently copies the specified number of elements from the
490 * specified storage location into the buffer at a particular
493 * If offset <= used() and offset + count > used(), the
494 * remaining data is simply tacked onto the end of the buffer
497 * It is an error for count to be greater than free() - offset.
500 * "data" is the buffer that contains the elements
501 * "count" is the number of elements
502 * "offset" is the buffer offset, default 0
504 void poke(const T
*data
, int offset
, size_t count
)
506 store
->poke(data
, offset
* sizeof(Elem
), count
* sizeof(Elem
));
510 * Writes the element into the buffer at its tail.
512 * It is an error to invoke this method if free() == 0.
514 * After this operation, at least 1 element may be unallocated.
517 * "valid" is the element
521 store
->fastput(& value
, sizeof(Elem
));
525 * Writes the element into the buffer at the specified offset.
527 * It is an error to invoke this method if free() == 0.
529 * After this operation, at least 1 element may be unallocated.
532 * "value" is the element
533 * "offset" is the buffer offset
535 void poke(T
&value
, int offset
)
537 poke(& value
, offset
, 1);
541 /*** Buffer to Buffer Transfers ***/
544 * Efficiently moves count bytes from the specified buffer into
545 * this one. In some cases, this may be a zero-copy operation.
547 * It is an error for count to be greater than inbuf.used().
549 * For maximum efficiency, choose as large a count as possible.
551 * After this operation, an indeterminate number of elements
552 * may be ungotten from inbuf.
555 * "inbuf" is the buffer from which to read
556 * "count" is the number of elements
558 void merge(Buffer
&inbuf
, size_t count
)
560 store
->merge(*inbuf
.store
, count
* sizeof(Elem
));
564 * Efficiently merges the entire contents of a buffer into this one.
566 * "inbuf" is the buffer from which to read
568 void merge(Buffer
&inbuf
)
570 merge(inbuf
, inbuf
.used());
577 * The generic buffer base type.
578 * To specialize buffers to add new functionality, declare a template
579 * specialization of this type that derives from WvBufBaseCommonImpl.
581 * See WvBufBaseCommonImpl<T>
582 * "T" is the type of object to store, must be a primitive or a struct
583 * without special initialization, copy, or assignment semantics
586 class WvBufBase
: public WvBufBaseCommonImpl
<T
>
589 explicit WvBufBase(WvBufStore
*store
) :
590 WvBufBaseCommonImpl
<T
>(store
) { }
596 * A buffer that wraps a pre-allocated array and provides
597 * read-write access to its elements.
599 * "T" is the type of object to store, must be a primitive or a struct
600 * without special initialization, copy, or assignment semantics
603 class WvInPlaceBufBase
: public WvBufBase
<T
>
608 WvInPlaceBufStore mystore
;
612 * Creates a new buffer backed by the supplied array.
614 * "_data" is the array of data to wrap
615 * "_avail" is the amount of data available for reading
616 * "_size" is the size of the array
617 * "_autofree" is if true, the array will be freed when discarded
619 WvInPlaceBufBase(T
*_data
, size_t _avail
, size_t _size
,
620 bool _autofree
= false) :
621 WvBufBase
<T
>(& mystore
),
622 mystore(sizeof(Elem
), _data
, _avail
* sizeof(Elem
),
623 _size
* sizeof(Elem
), _autofree
) { }
626 * Creates a new empty buffer backed by a new array.
628 * "_size" is the size of the array
630 explicit WvInPlaceBufBase(size_t _size
) :
631 WvBufBase
<T
>(& mystore
),
632 mystore(sizeof(Elem
), _size
* sizeof(Elem
)) { }
634 /** Creates a new empty buffer with no backing array. */
636 WvBufBase
<T
>(& mystore
),
637 mystore(sizeof(Elem
), NULL
, 0, 0, false) { }
640 * Destroys the buffer.
642 * Frees the underlying array if autofree().
645 virtual ~WvInPlaceBufBase() { }
648 * Returns the underlying array pointer.
650 * Returns: the element pointer
654 return static_cast<T
*>(mystore
.ptr());
658 * Returns the total size of the buffer.
660 * Returns: the number of elements
664 return mystore
.size() / sizeof(Elem
);
668 * Returns the autofree flag.
670 * Returns: the autofree flag
672 bool get_autofree() const
674 return mystore
.get_autofree();
678 * Sets or clears the autofree flag.
680 * "_autofree" is if true, the array will be freed when discarded
682 void set_autofree(bool _autofree
)
684 mystore
.set_autofree(_autofree
);
688 * Resets the underlying buffer pointer and properties.
690 * If the old and new buffer pointers differ and the old buffer
691 * was specified as autofree, the old buffer is destroyed.
693 * "_data" is the array of data to wrap
694 * "_avail" is the amount of data available for reading
695 * "_size" is the size of the array
696 * "_autofree" is if true, the array will be freed when discarded
698 void reset(T
*_data
, size_t _avail
, size_t _size
,
699 bool _autofree
= false)
701 mystore
.reset(_data
, _avail
* sizeof(Elem
),
702 _size
* sizeof(Elem
), _autofree
);
706 * Sets the amount of available data using the current buffer
707 * and resets the read index to the beginning of the buffer.
709 * "_avail" is the amount of data available for reading
711 void setavail(size_t _avail
)
713 mystore
.setavail(_avail
* sizeof(Elem
));
720 * A buffer that wraps a pre-allocated array and provides
721 * read-only access to its elements.
723 * "T" is the type of object to store, must be a primitive or a struct
724 * without special initialization, copy, or assignment semantics
727 class WvConstInPlaceBufBase
: public WvBufBase
<T
>
732 WvConstInPlaceBufStore mystore
;
736 * Creates a new buffer backed by the supplied array.
738 * "_data" is the array of data to wrap
739 * "_avail" is the amount of data available for reading
741 WvConstInPlaceBufBase(const T
*_data
, size_t _avail
) :
742 WvBufBase
<T
>(& mystore
),
743 mystore(sizeof(Elem
), _data
, _avail
* sizeof(Elem
)) { }
745 /** Creates a new empty buffer with no backing array. */
746 WvConstInPlaceBufBase() :
747 WvBufBase
<T
>(& mystore
),
748 mystore(sizeof(Elem
), NULL
, 0) { }
751 * Destroys the buffer.
753 * Never frees the underlying array.
756 virtual ~WvConstInPlaceBufBase() { }
759 * Returns the underlying array pointer.
761 * Returns: the element pointer
765 return static_cast<const T
*>(mystore
.ptr());
769 * Resets the underlying buffer pointer and properties.
771 * Never frees the old buffer.
774 * "_data" is the array of data to wrap
775 * "_avail" is the amount of data available for reading
777 void reset(const T
*_data
, size_t _avail
)
779 mystore
.reset(_data
, _avail
* sizeof(Elem
));
783 * Sets the amount of available data using the current buffer
784 * and resets the read index to the beginning of the buffer.
786 * "_avail" is the amount of data available for reading
788 void setavail(size_t _avail
)
790 mystore
.setavail(_avail
* sizeof(Elem
));
797 * A buffer that wraps a pre-allocated array and provides
798 * read-write access to its elements using a circular buffering
799 * scheme rather than a purely linear one, as used by
802 * When there is insufficient contigous free/used space to
803 * satisfy a read or write request, the data is automatically
804 * reordered in-place to coalesce the free/used spaces into
805 * sufficiently large chunks. The process may also be manually
806 * triggered to explicitly renormalize the array and shift its
807 * contents to the front.
809 * "T" is the type of object to store, must be a primitive or a struct
810 * without special initialization, copy, or assignment semantics
813 class WvCircularBufBase
: public WvBufBase
<T
>
818 WvCircularBufStore mystore
;
822 * Creates a new circular buffer backed by the supplied array.
824 * "_data" is the array of data to wrap
825 * "_avail" is the amount of data available for reading
826 * at the beginning of the buffer
827 * "_size" is the size of the array
828 * "_autofree" is if true, the array will be freed when discarded
830 WvCircularBufBase(T
*_data
, size_t _avail
, size_t _size
,
831 bool _autofree
= false) :
832 WvBufBase
<T
>(& mystore
),
833 mystore(sizeof(Elem
), _data
, _avail
* sizeof(Elem
),
834 _size
* sizeof(Elem
), _autofree
) { }
837 * Creates a new empty circular buffer backed by a new array.
839 * "_size" is the size of the array
841 explicit WvCircularBufBase(size_t _size
) :
842 WvBufBase
<T
>(& mystore
),
843 mystore(sizeof(Elem
), _size
* sizeof(Elem
)) { }
845 /** Creates a new empty buffer with no backing array. */
846 WvCircularBufBase() :
847 WvBufBase
<T
>(& mystore
),
848 mystore(sizeof(Elem
), NULL
, 0, 0, false) { }
851 * Destroys the buffer.
853 * Frees the underlying array if autofree().
856 virtual ~WvCircularBufBase() { }
859 * Returns the underlying array pointer.
861 * Returns: the element pointer
865 return static_cast<T
*>(mystore
.ptr());
869 * Returns the total size of the buffer.
871 * Returns: the number of elements
875 return mystore
.size() / sizeof(Elem
);
879 * Returns the autofree flag.
881 * Returns: the autofree flag
883 bool get_autofree() const
885 return mystore
.get_autofree();
889 * Sets or clears the autofree flag.
891 * "_autofree" is if true, the array will be freed when discarded
893 void set_autofree(bool _autofree
)
895 mystore
.set_autofree(_autofree
);
899 * Resets the underlying buffer pointer and properties.
901 * If the old and new buffer pointers differ and the old buffer
902 * was specified as autofree, the old buffer is destroyed.
904 * "_data" is the array of data to wrap
905 * "_avail" is the amount of data available for reading
906 * at the beginning of the buffer
907 * "_size" is the size of the array
908 * "_autofree" is if true, the array will be freed when discarded
910 void reset(T
*_data
, size_t _avail
, size_t _size
,
911 bool _autofree
= false)
913 mystore
.reset(_data
, _avail
* sizeof(Elem
),
914 _size
* sizeof(Elem
), _autofree
);
918 * Sets the amount of available data using the current buffer
919 * and resets the read index to the beginning of the buffer.
921 * "_avail" is the amount of data available for reading
922 * at the beginning of the buffer
924 void setavail(size_t _avail
)
926 mystore
.setavail(_avail
* sizeof(Elem
));
930 * Normalizes the arrangement of the data such that the
931 * contents of the buffer are stored at the beginning of
932 * the array starting with the next element that would be
933 * returned by get(size_t).
935 * After invocation, ungettable() may equal 0.
947 * A buffer that dynamically grows and shrinks based on demand.
949 * "T" is the type of object to store, must be a primitive or a struct
950 * without special initialization, copy, or assignment semantics
953 class WvDynBufBase
: public WvBufBase
<T
>
958 WvDynBufStore mystore
;
962 * Creates a new buffer.
964 * Provides some parameters for tuning response to buffer
967 * "_minalloc" is the minimum number of elements to allocate
968 * at once when creating a new internal buffer segment
969 * "_maxalloc" is the maximum number of elements to allocate
970 * at once when creating a new internal buffer segment
971 * before before reverting to a linear growth pattern
973 explicit WvDynBufBase(size_t _minalloc
= 1024,
974 size_t _maxalloc
= 1048576) :
975 WvBufBase
<T
>(& mystore
),
976 mystore(sizeof(Elem
), _minalloc
* sizeof(Elem
),
977 _maxalloc
* sizeof(Elem
)) { }
983 * A buffer that is always empty.
985 * "T" is the type of object to store, must be a primitive or a struct
986 * without special initialization, copy, or assignment semantics
989 class WvNullBufBase
: public WvBufBase
<T
>
994 WvNullBufStore mystore
;
997 /** Creates a new buffer. */
999 WvBufBase
<T
>(& mystore
),
1000 mystore(sizeof(Elem
)) { }
1006 * A buffer that acts like a cursor over a portion of another buffer.
1007 * The underlying buffer's get() position is not affected by
1008 * reading from this buffer.
1010 * "T" is the type of object to store, must be a primitive or a struct
1011 * without special initialization, copy, or assignment semantics
1014 class WvBufCursorBase
: public WvBufBase
<T
>
1019 WvBufCursorStore mystore
;
1023 * Creates a new buffer.
1025 * Does not take ownership of the supplied buffer.
1028 * "_buf" is a pointer to the buffer to be wrapped
1029 * "_start" is the buffer offset of the window start position
1030 * "_length" is the length of the window
1032 WvBufCursorBase(WvBufBase
<T
> &_buf
, int _start
,
1034 WvBufBase
<T
>(& mystore
),
1035 mystore(sizeof(Elem
), _buf
.getstore(),
1036 _start
* sizeof(Elem
), _length
* sizeof(Elem
)) { }
1041 * A buffer that provides a read-write view over another buffer
1042 * with a different datatype. Reading and writing through this
1043 * buffer implicitly performs the equivalent of reinterpret_cast
1046 * Most useful for manipulating data backed by a raw memory buffer.
1048 * "T" is the type of object to store, must be a primitive or a struct
1049 * without special initialization, copy, or assignment semantics
1052 class WvBufViewBase
: public WvBufBase
<T
>
1056 * Creates a new buffer.
1058 * Does not take ownership of the supplied buffer.
1061 * "_buf" is a pointer to the buffer to be wrapped
1063 template<typename S
>
1064 WvBufViewBase(WvBufBase
<S
> &_buf
) :
1065 WvBufBase
<T
>(_buf
.getstore()) { }
1068 #endif // __WVBUFFERBASE_H