Add gwbuf_compare
With gwbuf_compare the content of two GWBUFs can be compared.
This commit is contained in:
@ -211,6 +211,26 @@ extern void gwbuf_free(GWBUF *buf);
|
||||
*/
|
||||
extern GWBUF *gwbuf_clone(GWBUF *buf);
|
||||
|
||||
/**
|
||||
* Compare two GWBUFs. Two GWBUFs are considered identical if their
|
||||
* content is identical, irrespective of whether one is segmented and
|
||||
* the other is not.
|
||||
*
|
||||
* @param lhs One GWBUF
|
||||
* @param rhs Another GWBUF
|
||||
*
|
||||
* @return 0 if the content is identical,
|
||||
* -1 if @c lhs is less than @c rhs, and
|
||||
* 1 if @c lhs is more than @c rhs.
|
||||
*
|
||||
* @attention A NULL @c GWBUF is considered to be less than a non-NULL one,
|
||||
* and a shorter @c GWBUF less than a longer one. Otherwise the
|
||||
* the sign of the return value is determined by the sign of the
|
||||
* difference between the first pair of bytes (interpreted as
|
||||
* unsigned char) that differ in lhs and rhs.
|
||||
*/
|
||||
extern int gwbuf_compare(const GWBUF* lhs, const GWBUF* rhs);
|
||||
|
||||
/**
|
||||
* Append a buffer onto a linked list of buffer structures.
|
||||
*
|
||||
|
@ -439,6 +439,122 @@ GWBUF* gwbuf_split(GWBUF **buf, size_t length)
|
||||
return head;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a byte from a GWBUF at a particular offset. Intended to be use like:
|
||||
*
|
||||
* GWBUF *buf = ...;
|
||||
* size_t offset = 0;
|
||||
* uint8_t c;
|
||||
*
|
||||
* while (gwbuf_get_byte(&buf, &offset, &c))
|
||||
* {
|
||||
* printf("%c", c);
|
||||
* }
|
||||
*
|
||||
* @param buf Pointer to pointer to GWBUF. The GWBUF pointed to may be adjusted
|
||||
* as a result of the call.
|
||||
* @param offset Pointer to variable containing the offset. Value of variable will
|
||||
* incremented as a result of the call.
|
||||
* @param b Pointer to variable that upon successful return will contain the
|
||||
* next byte.
|
||||
*
|
||||
* @return True, if offset refers to a byte in the GWBUF.
|
||||
*/
|
||||
static inline bool gwbuf_get_byte(const GWBUF** buf, size_t* offset, uint8_t* b)
|
||||
{
|
||||
bool rv = false;
|
||||
|
||||
// Ignore NULL buffer and walk past empty or too short buffers.
|
||||
while (*buf && (GWBUF_LENGTH(*buf) <= *offset))
|
||||
{
|
||||
*offset -= GWBUF_LENGTH(*buf);
|
||||
*buf = (*buf)->next;
|
||||
}
|
||||
|
||||
ss_dassert(!*buf || (GWBUF_LENGTH(*buf) > *offset));
|
||||
|
||||
if (*buf)
|
||||
{
|
||||
*b = *(GWBUF_DATA(*buf) + *offset);
|
||||
*offset += 1;
|
||||
|
||||
rv = true;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int gwbuf_compare(const GWBUF* lhs, const GWBUF* rhs)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if ((lhs == NULL) && (rhs == NULL))
|
||||
{
|
||||
rv = 0;
|
||||
}
|
||||
else if (lhs == NULL)
|
||||
{
|
||||
ss_dassert(rhs);
|
||||
rv = -1;
|
||||
}
|
||||
else if (rhs == NULL)
|
||||
{
|
||||
ss_dassert(lhs);
|
||||
rv = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ss_dassert(lhs && rhs);
|
||||
|
||||
size_t llen = gwbuf_length(lhs);
|
||||
size_t rlen = gwbuf_length(rhs);
|
||||
|
||||
if (llen < rlen)
|
||||
{
|
||||
rv = -1;
|
||||
}
|
||||
else if (rlen < llen)
|
||||
{
|
||||
rv = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ss_dassert(llen == rlen);
|
||||
|
||||
rv = 0;
|
||||
size_t i = 0;
|
||||
size_t loffset = 0;
|
||||
size_t roffset = 0;
|
||||
|
||||
while ((rv == 0) && (i < llen))
|
||||
{
|
||||
uint8_t lc;
|
||||
uint8_t rc;
|
||||
|
||||
ss_debug(bool rv1 =) gwbuf_get_byte(&lhs, &loffset, &lc);
|
||||
ss_debug(bool rv2 =) gwbuf_get_byte(&rhs, &roffset, &rc);
|
||||
|
||||
ss_dassert(rv1 && rv2);
|
||||
|
||||
rv = (int)lc - (int)rc;
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
if (rv < 0)
|
||||
{
|
||||
rv = -1;
|
||||
}
|
||||
else if (rv > 0)
|
||||
{
|
||||
rv = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
GWBUF *
|
||||
gwbuf_append(GWBUF *head, GWBUF *tail)
|
||||
{
|
||||
|
@ -316,6 +316,78 @@ void test_consume()
|
||||
consume_buffer(n_buffers - 1, -1);
|
||||
}
|
||||
|
||||
void test_compare()
|
||||
{
|
||||
static const uint8_t data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
|
||||
ss_dfprintf(stderr, "testbuffer : testing GWBUF comparisons\n");
|
||||
|
||||
GWBUF* lhs = NULL;
|
||||
GWBUF* rhs = NULL;
|
||||
|
||||
// Both NULL
|
||||
ss_dassert(gwbuf_compare(lhs, rhs) == 0);
|
||||
|
||||
// Either (but not both) NULL
|
||||
lhs = gwbuf_alloc_and_load(10, data);
|
||||
ss_dassert(gwbuf_compare(lhs, rhs) > 0);
|
||||
ss_dassert(gwbuf_compare(rhs, lhs) < 0);
|
||||
|
||||
// The same array
|
||||
ss_dassert(gwbuf_compare(lhs, lhs) == 0);
|
||||
|
||||
// Identical array
|
||||
gwbuf_free(rhs);
|
||||
rhs = gwbuf_alloc_and_load(10, data);
|
||||
ss_dassert(gwbuf_compare(lhs, rhs) == 0);
|
||||
|
||||
// One shorter
|
||||
gwbuf_free(rhs);
|
||||
rhs = gwbuf_alloc_and_load(9, data + 1);
|
||||
ss_dassert(gwbuf_compare(lhs, rhs) > 0);
|
||||
ss_dassert(gwbuf_compare(rhs, lhs) < 0);
|
||||
|
||||
// One segmented, but otherwise identical.
|
||||
gwbuf_free(rhs);
|
||||
rhs = NULL;
|
||||
rhs = gwbuf_append(rhs, gwbuf_alloc_and_load(3, data));
|
||||
rhs = gwbuf_append(rhs, gwbuf_alloc_and_load(3, data + 3));
|
||||
rhs = gwbuf_append(rhs, gwbuf_alloc_and_load(4, data + 3 + 3));
|
||||
|
||||
ss_dassert(gwbuf_compare(lhs, rhs) == 0);
|
||||
ss_dassert(gwbuf_compare(rhs, rhs) == 0);
|
||||
|
||||
// Both segmented, but otherwise identical.
|
||||
gwbuf_free(lhs);
|
||||
lhs = NULL;
|
||||
lhs = gwbuf_append(lhs, gwbuf_alloc_and_load(5, data));
|
||||
lhs = gwbuf_append(lhs, gwbuf_alloc_and_load(5, data + 5));
|
||||
|
||||
ss_dassert(gwbuf_compare(lhs, rhs) == 0);
|
||||
ss_dassert(gwbuf_compare(rhs, lhs) == 0);
|
||||
|
||||
// Both segmented and of same length, but different.
|
||||
gwbuf_free(lhs);
|
||||
lhs = NULL;
|
||||
lhs = gwbuf_append(lhs, gwbuf_alloc_and_load(5, data + 5)); // Values in different order
|
||||
lhs = gwbuf_append(lhs, gwbuf_alloc_and_load(5, data));
|
||||
|
||||
ss_dassert(gwbuf_compare(lhs, rhs) > 0); // 5 > 1
|
||||
ss_dassert(gwbuf_compare(rhs, lhs) < 0); // 5 > 1
|
||||
|
||||
// Identical, but one containing empty segments.
|
||||
gwbuf_free(rhs);
|
||||
rhs = NULL;
|
||||
rhs = gwbuf_append(rhs, gwbuf_alloc_and_load(0, data));
|
||||
rhs = gwbuf_append(rhs, gwbuf_alloc_and_load(5, data + 5));
|
||||
rhs = gwbuf_append(rhs, gwbuf_alloc_and_load(0, data));
|
||||
rhs = gwbuf_append(rhs, gwbuf_alloc_and_load(5, data));
|
||||
rhs = gwbuf_append(rhs, gwbuf_alloc_and_load(0, data));
|
||||
|
||||
ss_dassert(gwbuf_compare(lhs, rhs) == 0);
|
||||
ss_dassert(gwbuf_compare(rhs, lhs) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* test1 Allocate a buffer and do lots of things
|
||||
*
|
||||
@ -433,6 +505,7 @@ test1()
|
||||
test_split();
|
||||
test_load_and_copy();
|
||||
test_consume();
|
||||
test_compare();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user