diff --git a/doc/internals/buffer-api.txt b/doc/internals/buffer-api.txt index c318da463..7938f4c9a 100644 --- a/doc/internals/buffer-api.txt +++ b/doc/internals/buffer-api.txt @@ -459,6 +459,13 @@ b_rep_blk() | buffer *buf | writes the block at position | | done. If is null, the | | pointer is allowed to be null, in | | order to erase a block +--------------------+------------------+--------------------------------------- +b_xfer() | buffer *src | transfers at most bytes from + | buffer *dst | buffer to buffer and + | size_t cout | returns the number of bytes copied. + | ret: size_t | The bytes are removed from and + | | added to . The caller guarantees + | | that is <= b_room(dst) ====================+==================+======================================= diff --git a/include/common/buf.h b/include/common/buf.h index b93ef9946..e72de911a 100644 --- a/include/common/buf.h +++ b/include/common/buf.h @@ -514,6 +514,42 @@ static inline size_t b_putblk(struct buffer *b, const char *blk, size_t len) return len; } +/* b_xfer() : transfers at most bytes from buffer to buffer + * and returns the number of bytes copied. The bytes are removed from and + * added to . The caller is responsible for ensuring that is not + * larger than b_room(dst). + */ +static inline size_t b_xfer(struct buffer *dst, struct buffer *src, size_t count) +{ + size_t ret, block1, block2; + + ret = 0; + if (!count) + goto leave; + + ret = b_data(src); + if (!ret) + goto leave; + + if (ret > count) + ret = count; + + block1 = b_contig_data(src, 0); + if (block1 > ret) + block1 = ret; + block2 = ret - block1; + + if (block1) + __b_putblk(dst, b_head(src), block1); + + if (block2) + __b_putblk(dst, b_peek(src, block1), block2); + + b_del(src, ret); + leave: + return ret; +} + /* b_rep_blk() : writes the block at position which must be in * buffer , and moves the part between and the buffer's tail just * after the end of the copy of . This effectively replaces the part