mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-03-11 05:48:41 +00:00
MINOR: buffer: add a few basic functions for the new API
Here's the list of newly introduced functions : - b_data(), returning the total amount of data in the buffer (currently i+o) - b_orig(), returning the origin of the storage area, that is, the place of position 0. - b_wrap(), pointer to wrapping point (currently data+size) - b_size(), returning the size of the buffer - b_room(), returning the amount of bytes left available - b_full(), returning true if the buffer is full, otherwise false - b_stop(), pointer to end of data mark (currently p+i), used to compute distances or a stop pointer for a loop. - b_peek(), this one will help make the transition to the new buffer model. It returns a pointer to a position in the buffer known from an offest relative to the beginning of the data in the buffer. Thus, we can replace the following occurrences : bo_ptr(b) => b_peek(b, 0); bo_end(b) => b_peek(b, b->o); bi_ptr(b) => b_peek(b, b->o); bi_end(b) => b_peek(b, b->i + b->o); b_ptr(b, ofs) => b_peek(b, b->o + ofs); - b_head(), pointer to the beginning of data (currently bo_ptr()) - b_tail(), pointer to first free place (currently bi_ptr()) - b_next() / b_next_ofs(), pointer to the next byte, taking wrapping into account. - b_dist(), returning the distance between two pointers belonging to a buffer - b_reset(), which resets the buffer - b_space_wraps(), indicating if the free space wraps around the buffer - b_almost_full(), indicating if 3/4 or more of the buffer are used Some of these are provided with the unchecked variants using the "__" prefix, or with the "_ofs" suffix indicating they return a relative position to the buffer's origin instead of a pointer. Cc: Olivier Houchard <ohouchard@haproxy.com>
This commit is contained in:
parent
506a29ac6e
commit
bbc68df330
@ -30,7 +30,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/* Structure defining a buffer's head */
|
||||
struct buffer {
|
||||
char *p; /* buffer's start pointer, separates in and out data */
|
||||
@ -41,6 +40,257 @@ struct buffer {
|
||||
};
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
/* Functions used to compute offsets and pointers. Most of them exist in */
|
||||
/* both wrapping-safe and unchecked ("__" prefix) variants. Some returning */
|
||||
/* a pointer are also provided with an "_ofs" suffix when they return an */
|
||||
/* offset relative to the storage area. */
|
||||
/***************************************************************************/
|
||||
|
||||
/* b_orig() : returns the pointer to the origin of the storage, which is the
|
||||
* location of byte at offset zero. This is mostly used by functions which
|
||||
* handle the wrapping by themselves.
|
||||
*/
|
||||
static inline char *b_orig(const struct buffer *b)
|
||||
{
|
||||
return (char *)b->data;
|
||||
}
|
||||
|
||||
/* b_size() : returns the size of the buffer. */
|
||||
static inline size_t b_size(const struct buffer *b)
|
||||
{
|
||||
return b->size;
|
||||
}
|
||||
|
||||
/* b_wrap() : returns the pointer to the wrapping position of the buffer area,
|
||||
* which is by definition the first byte not part of the buffer.
|
||||
*/
|
||||
static inline char *b_wrap(const struct buffer *b)
|
||||
{
|
||||
return (char *)b->data + b->size;
|
||||
}
|
||||
|
||||
/* b_data() : returns the number of bytes present in the buffer. */
|
||||
static inline size_t b_data(const struct buffer *b)
|
||||
{
|
||||
return b->i + b->o;
|
||||
}
|
||||
|
||||
/* b_room() : returns the amount of room left in the buffer */
|
||||
static inline size_t b_room(const struct buffer *b)
|
||||
{
|
||||
return b->size - b_data(b);
|
||||
}
|
||||
|
||||
/* b_full() : returns true if the buffer is full. */
|
||||
static inline size_t b_full(const struct buffer *b)
|
||||
{
|
||||
return !b_room(b);
|
||||
}
|
||||
|
||||
|
||||
/* b_stop() : returns the pointer to the byte following the end of the buffer,
|
||||
* which may be out of the buffer if the buffer ends on the last byte of the
|
||||
* area.
|
||||
*/
|
||||
static inline size_t __b_stop_ofs(const struct buffer *b)
|
||||
{
|
||||
return b->p - b->data + b->i;
|
||||
}
|
||||
|
||||
static inline const char *__b_stop(const struct buffer *b)
|
||||
{
|
||||
return b->p + b->i;
|
||||
}
|
||||
|
||||
static inline size_t b_stop_ofs(const struct buffer *b)
|
||||
{
|
||||
size_t stop = __b_stop_ofs(b);
|
||||
|
||||
if (stop > b->size)
|
||||
stop -= b->size;
|
||||
return stop;
|
||||
}
|
||||
|
||||
static inline const char *b_stop(const struct buffer *b)
|
||||
{
|
||||
return b->data + b_stop_ofs(b);
|
||||
}
|
||||
|
||||
|
||||
/* b_peek() : returns a pointer to the data at position <ofs> relative to the
|
||||
* head of the buffer. Will typically point to input data if called with the
|
||||
* amount of output data. The wrapped versions will only support wrapping once
|
||||
* before the beginning or after the end.
|
||||
*/
|
||||
static inline size_t __b_peek_ofs(const struct buffer *b, size_t ofs)
|
||||
{
|
||||
return b->p - b->data + ofs - b->o;
|
||||
}
|
||||
|
||||
static inline char *__b_peek(const struct buffer *b, size_t ofs)
|
||||
{
|
||||
return b->p - b->o + ofs;
|
||||
}
|
||||
|
||||
static inline size_t b_peek_ofs(const struct buffer *b, size_t ofs)
|
||||
{
|
||||
size_t ret = __b_peek_ofs(b, ofs);
|
||||
|
||||
if (ret >= b->size) {
|
||||
/* wraps either up or down */
|
||||
if ((ssize_t)ret < 0)
|
||||
ret += b->size;
|
||||
else
|
||||
ret -= b->size;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline char *b_peek(const struct buffer *b, size_t ofs)
|
||||
{
|
||||
return (char *)b->data + b_peek_ofs(b, ofs);
|
||||
}
|
||||
|
||||
|
||||
/* b_head() : returns the pointer to the buffer's head, which is the location
|
||||
* of the next byte to be dequeued. Note that for buffers of size zero, the
|
||||
* returned pointer may be outside of the buffer or even invalid.
|
||||
*/
|
||||
static inline size_t __b_head_ofs(const struct buffer *b)
|
||||
{
|
||||
return __b_peek_ofs(b, 0);
|
||||
}
|
||||
|
||||
static inline char *__b_head(const struct buffer *b)
|
||||
{
|
||||
return __b_peek(b, 0);
|
||||
}
|
||||
|
||||
static inline size_t b_head_ofs(const struct buffer *b)
|
||||
{
|
||||
return b_peek_ofs(b, 0);
|
||||
}
|
||||
|
||||
static inline char *b_head(const struct buffer *b)
|
||||
{
|
||||
return b_peek(b, 0);
|
||||
}
|
||||
|
||||
|
||||
/* b_tail() : returns the pointer to the tail of the buffer, which is the
|
||||
* location of the first byte where it is possible to enqueue new data. Note
|
||||
* that for buffers of size zero, the returned pointer may be outside of the
|
||||
* buffer or even invalid.
|
||||
*/
|
||||
static inline size_t __b_tail_ofs(const struct buffer *b)
|
||||
{
|
||||
return __b_peek_ofs(b, b_data(b));
|
||||
}
|
||||
|
||||
static inline char *__b_tail(const struct buffer *b)
|
||||
{
|
||||
return __b_peek(b, b_data(b));
|
||||
}
|
||||
|
||||
static inline size_t b_tail_ofs(const struct buffer *b)
|
||||
{
|
||||
return b_peek_ofs(b, b_data(b));
|
||||
}
|
||||
|
||||
static inline char *b_tail(const struct buffer *b)
|
||||
{
|
||||
return b_peek(b, b_data(b));
|
||||
}
|
||||
|
||||
|
||||
/* b_next() : for an absolute pointer <p> or a relative offset <o> pointing to
|
||||
* a valid location within buffer <b>, returns either the absolute pointer or
|
||||
* the relative offset pointing to the next byte, which usually is at (p + 1)
|
||||
* unless p reaches the wrapping point and wrapping is needed.
|
||||
*/
|
||||
static inline size_t b_next_ofs(const struct buffer *b, size_t o)
|
||||
{
|
||||
o++;
|
||||
if (o == b->size)
|
||||
o = 0;
|
||||
return o;
|
||||
}
|
||||
|
||||
static inline char *b_next(const struct buffer *b, const char *p)
|
||||
{
|
||||
p++;
|
||||
if (p == b_wrap(b))
|
||||
p = b_orig(b);
|
||||
return (char *)p;
|
||||
}
|
||||
|
||||
/* b_dist() : returns the distance between two pointers, taking into account
|
||||
* the ability to wrap around the buffer's end. The operation is not defined if
|
||||
* either of the pointers does not belong to the buffer or if their distance is
|
||||
* greater than the buffer's size.
|
||||
*/
|
||||
static inline size_t b_dist(const struct buffer *b, const char *from, const char *to)
|
||||
{
|
||||
ssize_t dist = to - from;
|
||||
|
||||
dist += dist < 0 ? b_size(b) : 0;
|
||||
return dist;
|
||||
}
|
||||
|
||||
/* b_almost_full() : returns 1 if the buffer uses at least 3/4 of its capacity,
|
||||
* otherwise zero. Buffers of size zero are considered full.
|
||||
*/
|
||||
static inline int b_almost_full(const struct buffer *b)
|
||||
{
|
||||
return b_data(b) >= b_size(b) * 3 / 4;
|
||||
}
|
||||
|
||||
/* b_space_wraps() : returns non-zero only if the buffer's free space wraps :
|
||||
* [ |oooo| ] => yes
|
||||
* [ |iiii| ] => yes
|
||||
* [ |oooo|iiii| ] => yes
|
||||
* [oooo| ] => no
|
||||
* [ |oooo] => no
|
||||
* [iiii| ] => no
|
||||
* [ |iiii] => no
|
||||
* [oooo|iiii| ] => no
|
||||
* [ |oooo|iiii] => no
|
||||
* [iiii| |oooo] => no
|
||||
* [oo|iiii| |oo] => no
|
||||
* [iiii| |oo|ii] => no
|
||||
* [oooooooooo|iiiiiiiiiii] => no
|
||||
* [iiiiiiiiiiiii|oooooooo] => no
|
||||
*
|
||||
* So the only case where the buffer does not wrap is when there's data either
|
||||
* at the beginning or at the end of the buffer. Thus we have this :
|
||||
* - if (head <= 0) ==> doesn't wrap
|
||||
* - if (tail >= size) ==> doesn't wrap
|
||||
* - otherwise wraps
|
||||
*/
|
||||
static inline int b_space_wraps(const struct buffer *b)
|
||||
{
|
||||
if ((ssize_t)__b_head_ofs(b) <= 0)
|
||||
return 0;
|
||||
if (__b_tail_ofs(b) >= b_size(b))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************/
|
||||
/* Functions used to modify the buffer state */
|
||||
/*********************************************/
|
||||
|
||||
/* b_reset() : resets a buffer. The size is not touched. */
|
||||
static inline void b_reset(struct buffer *b)
|
||||
{
|
||||
b->o = 0;
|
||||
b->i = 0;
|
||||
b->p = b_orig(b);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _COMMON_BUF_H */
|
||||
|
||||
|
@ -379,9 +379,7 @@ static inline int buffer_almost_full(const struct buffer *buf)
|
||||
if (buf == &buf_empty)
|
||||
return 0;
|
||||
|
||||
if (!buf->size || buffer_total_space(buf) < buf->size / 4)
|
||||
return 1;
|
||||
return 0;
|
||||
return b_almost_full(buf);
|
||||
}
|
||||
|
||||
/* Cut the first <n> pending bytes in a contiguous buffer. It is illegal to
|
||||
@ -639,15 +637,6 @@ static inline int bi_getblk_nc(struct buffer *buf, char **blk1, int *len1, char
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Resets a buffer. The size is not touched. */
|
||||
static inline void b_reset(struct buffer *buf)
|
||||
{
|
||||
buf->o = 0;
|
||||
buf->i = 0;
|
||||
buf->p = buf->data;
|
||||
|
||||
}
|
||||
|
||||
/* Allocates a buffer and replaces *buf with this buffer. If no memory is
|
||||
* available, &buf_wanted is used instead. No control is made to check if *buf
|
||||
* already pointed to another buffer. The allocated buffer is returned, or
|
||||
|
Loading…
Reference in New Issue
Block a user