commit ee2aeefa170b9806e719723f94ba933c90a9ae8b
parent cdb1f983a89439ad11d51fe96fc5838cca9d1b3f
Author: Laurent Bercot <ska-skaware@skarnet.org>
Date: Wed, 4 Jan 2023 16:32:21 +0000
Add siovec doc, fix siovec_trunc, credit Ermine
Signed-off-by: Laurent Bercot <ska@appnovation.com>
Diffstat:
3 files changed, 120 insertions(+), 6 deletions(-)
diff --git a/AUTHORS b/AUTHORS
@@ -13,6 +13,7 @@ Contributors:
Shengjing Zhu <zhsj@debian.org>
Colin Booth <colin@heliocat.net>
Petr Vanek <arkamar@atlas.cz>
+ Peter Shkenev <mustela@erminea.space>
Thanks to:
Jean Marot <jean.marot@skarnet.org>
diff --git a/doc/libstddjb/siovec.html b/doc/libstddjb/siovec.html
@@ -21,7 +21,120 @@
<h1> The <tt>skalibs/siovec.h</tt> header </h1>
<p>
- TODO: write this documentation page. (Sorry!)
+ The following functions are declared in the <tt>skalibs/siovec.h</tt> header
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> Purpose </h2>
+
+<p>
+ These functions manipulate arrays of <tt>struct iovec</tt> containing
+ranges of bytes, handling them as contiguous arrays. They're used, for
+instance, in the skalibs implementation of circular buffers.
+</p>
+
+<h2> Functions </h2>
+
+<p>
+<code> size_t siovec_len (struct iovec const *v, unsigned int n) </code> <br>
+Returns the sum of the first <em>n</em> <tt>iov_len</tt> fields of the
+<em>v</em> array - i.e. the total number of bytes contained in the
+array represented by <em>v</em> of length <em>n</em>.
+</p>
+
+<p>
+<code> size_t siovec_gather (struct iovec const *v, unsigned int n, char *s, size_t max) </code> <br>
+Gathers all the data scattered in ranges described by <em>v</em> of length
+<em>n</em> into the space pointed to by <em>s</em>.
+Specifically: the first <tt>v[0].iov_len</tt> bytes pointed to by
+<tt>v[0].iov_base</tt> bytes are copied to <em>s</em>, then the first
+<tt>v[1].iov_len</tt> bytes pointed to by <tt>v[1].iov_base</tt> are
+appended to it, and so on, <em>n</em> times.
+The function copies no more than <tt>max</tt> bytes. It
+returns the total amount of bytes copied.
+</p>
+
+<p>
+<code> size_t siovec_scatter (struct iovec const *v, unsigned int n, char const *s, size_t len) </code> <br>
+Scatters <em>len</em> bytes of data from <em>s</em> into the byte ranges
+represented by array <em>v</em> of length <em>n</em>. (This is the opposite
+of the <tt>siovec_gather()</tt> function.)
+The first <tt>v[0].iov_len</tt> bytes of
+<tt>s</tt> are copied to <tt>v[0].iov_base</tt>, then the following
+<tt>v[1].iov_len</tt> bytes of <em>s</em> are copied to
+<tt>v[1].iov_base</tt>, and so on up to <em>len</em> bytes or until
+if the scatter array is full, i.e. <tt>siovec_len(v, n)</tt> bytes
+have been copied. The function returns the total amount of bytes copied.
+</p>
+
+<p>
+<code> size_t siovec_deal (struct iovec const *vj, unsigned int nj, struct iovec const *vi, unsigned int ni) </code> <br>
+Copies the data contained in the ranges represented by the array <em>vi</em> of
+length <em>ni</em> to the ranges represented by the array <em>vj</em> of length
+<em>nj</em>.
+The first <tt>vi[0].iov_len</tt> bytes pointed to by <tt>vi[0].iov_base</tt>
+are copied to <tt>vj[0].iov_base</tt>, up to <tt>vj[0].iov_len</tt> bytes,
+moving on to <tt>vj[1].iov_base</tt> if it overflows; then the bytes pointed
+to by <tt>vi[1].iov_base</tt> are copied to what space remains wherever the
+writing pointer is, and so on until all the bytes in the ranges described by
+<em>vi</em> have been copied or there is no more room left in the ranges
+described by <em>vj</em>.
+The function returns the total amount of bytes copied.
+</p>
+
+<p>
+<code> size_t siovec_seek (struct iovec *v, unsigned int n, size_t len) </code> <br>
+Does the equivalent of <tt>p += len;</tt> if the byte ranges represented by
+array <em>v</em> of size <em>n</em> were a single byte array pointed by <tt>p</tt>.
+If <tt>v[0].iov_len</tt> is lesser than <em>len</em>, then <tt>v[0]</tt> is
+zeroed out (set to <tt>{ .iov_base = 0, .iov_len = 0 }</tt>), <tt>v[0].iov_len</tt>
+bytes are deduced from <em>len</em>, and the same operation is repeated with
+<tt>v[1]</tt>, and so on. If every iovec gets zeroed out, the operation stops;
+but if a <tt>v[i].iov_len</tt> is greater than the
+remaining amount of bytes to deduce, that amount is substracted from
+<tt>v[i].iov_len</tt> and added to <tt>v[i].iov_base</tt>. The function returns
+the total number of bytes that have been deduced.
+</p>
+
+<p>
+<code> unsigned int siovec_trunc (struct iovec *v, unsigned int n, size_t len) </code> <br>
+Truncates the last fields of <em>v</em> of size <em>n</em> so that the byte
+ranges it represents have a total length of <em>len</em> or less. The
+<tt>iov_len</tt> field of <tt>v[n-1]</tt> is decreased by len; if it would
+be negative, then it's zeroed out and the remainder is taken from <tt>v[n-2]</tt>
+instead, and so on. The function returns the new size of array <em>v</em>
+with the tailing zeroed out members removed. It can only return 0 if <em>len</em>
+is 0, which means all of <em>v</em> has been zeroed out.
+</p>
+
+<p>
+<code> size_t siovec_bytechr (struct iovec const *v, unsigned int n, char c) </code> <br>
+Looks for the first occurence of <em>c</em> among the byte ranges represented by the members
+of <em>v</em>. Returns its cumulative index, i.e. the position that <em>c</em>
+would have if the byte ranges pointed to by members of <em>v</em> were a
+single array. If there are no occurences of <em>c</em>, the function retunrs
+<tt>siovec_len(v, n)</tt>.
+</p>
+
+<p>
+<code> size_t siovec_bytein (struct iovec const *v, unsigned int n, char const *sep, size_t seplen) </code> <br>
+Looks for the first occurence of any byte from the <em>sep</em> array of size
+<em>seplen</em> among the byte ranges represented by the members of array <em>v</em>
+of size <em>n</em>, and returns the cumulative index of the first one it finds.
+</p>
+
+<p>
+<code> size_t siovec_search (struct iovec const *v, unsigned int n, char const *needle, size_t nlen) </code> <br>
+Looks for the string (as in array of bytes: null characters are supported)
+<em>needle</em> of size <em>nlen</em> in the byte ranges represented by the
+members of array <em>v</em> of size <em>n</em>, and returns the cumulative
+index of the first occurrence it finds, or <tt>siovec_len(v, n)</tt> if it
+cannot find one. Split strings <strong>are</strong> supported: if <em>needle</em>
+starts at position <tt>v[i].iov_base + pos</tt> but is cut because it
+reaches <tt>v[i].iov_len</tt> midstring, and the rest of <em>needle</em>
+is available at <tt>v[i+1].iov_base</tt>, then the function will find it
+(and return <em>pos</em> plus the sum length of all the <em>v</em> members
+before <em>i</em>).
</p>
</body>
diff --git a/src/libstddjb/siovec_trunc.c b/src/libstddjb/siovec_trunc.c
@@ -6,13 +6,13 @@
unsigned int siovec_trunc (struct iovec *v, unsigned int n, size_t len)
{
size_t w = siovec_len(v, n) ;
- unsigned int i = n ;
if (w < len) return n ;
len = w - len ;
- while (len && i--)
+ while (n && len)
{
- w = len > v[i].iov_len ? v[i].iov_len : len ;
- v[i].iov_len -= w ; len -= w ;
+ w = len > v[n-1].iov_len ? v[n-1].iov_len : len ;
+ v[n-1].iov_len -= w ; len -= w ;
+ if (!v[n-1].iov_len) n-- ;
}
- return i ;
+ return n ;
}