X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Fsilcbuffer.h;h=5ce671175b628994820e5edd63a20efb026cb504;hb=52e57c880aba9c5e89f59d962eb9af75670b76e0;hp=407ae219a3ad4d22731aa30f518eb0297bb2b6a2;hpb=b62e4fb200b67ecc35a6da962619027c9b77f35e;p=silc.git diff --git a/lib/silcutil/silcbuffer.h b/lib/silcutil/silcbuffer.h index 407ae219..5ce67117 100644 --- a/lib/silcutil/silcbuffer.h +++ b/lib/silcutil/silcbuffer.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1998 - 2006 Pekka Riikonen + Copyright (C) 1998 - 2007 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -105,9 +105,12 @@ * section. Tail section can be pulled towards end, and thus the data * section becomes larger. * + * SILC Buffer is not thread-safe. If the same SilcBuffer context must be + * used in multithreaded environment concurrency control must be employed. + * * SOURCE */ -typedef struct { +typedef struct SilcBufferObject { unsigned char *head; unsigned char *data; unsigned char *tail; @@ -117,82 +120,114 @@ typedef struct { /* Macros */ -/****d* silcutil/SilcBufferAPI/silc_buffer_truelen +/****f* silcutil/SilcBufferAPI/silc_buffer_data * * NAME * - * #define silc_buffer_truelen(buffer) + * unsigned char *silc_buffer_data(SilcBuffer sb) * * DESCRIPTION * - * Returns the true length of the buffer. + * Returns pointer to the data area of the buffer. * * SOURCE */ -#define silc_buffer_truelen(x) (SilcUInt32)((x)->end - (x)->head) +#define silc_buffer_data(x) (x)->data /***/ -/****d* silcutil/SilcBufferAPI/silc_buffer_len +/****f* silcutil/SilcBufferAPI/silc_buffer_datalen * * NAME * - * #define silc_buffer_len(buffer) + * #define silc_buffer_datalen ... * * DESCRIPTION * - * Returns the current length of the data area of the buffer. + * Macro that can be used in function argument list to give the data + * pointer and the data length, instead of calling both silc_buffer_data + * and silc_buffer_len separately. + * + * EXAMPLE + * + * // Following are the same thing + * silc_foo_function(foo, silc_buffer_datalen(buf)); + * silc_foo_function(foo, silc_buffer_data(buf), silc_buffer_len(buf)); * * SOURCE */ -#define silc_buffer_len(x) (SilcUInt32)((x)->tail - (x)->data) +#define silc_buffer_datalen(x) (x) ? silc_buffer_data((x)) : NULL, \ + (x) ? silc_buffer_len((x)) : 0 /***/ -/****d* silcutil/SilcBufferAPI/silc_buffer_headlen +/* Inline functions */ + +/****d* silcutil/SilcBufferAPI/silc_buffer_truelen * * NAME * - * #define silc_buffer_headlen(buffer) + * SilcUInt32 silc_buffer_truelen(SilcBuffer sb) * * DESCRIPTION * - * Returns the current length of the head data area of the buffer. + * Returns the true length of the buffer. * - * SOURCE - */ -#define silc_buffer_headlen(x) (SilcUInt32)((x)->data - (x)->head) -/***/ + ***/ +static inline +SilcUInt32 silc_buffer_truelen(SilcBuffer x) +{ + return (SilcUInt32)(x->end - x->head); +} -/****d* silcutil/SilcBufferAPI/silc_buffer_taillen +/****d* silcutil/SilcBufferAPI/silc_buffer_len * * NAME * - * #define silc_buffer_taillen(buffer) + * SilcUInt32 silc_buffer_len(SilcBuffer sb) * * DESCRIPTION * - * Returns the current length of the tail data area of the buffer. + * Returns the current length of the data area of the buffer. * - * SOURCE - */ -#define silc_buffer_taillen(x) (SilcUInt32)((x)->end - (x)->tail) -/***/ + ***/ +static inline +SilcUInt32 silc_buffer_len(SilcBuffer x) +{ + return (SilcUInt32)(x->tail - x->data); +} -/****f* silcutil/SilcBufferAPI/silc_buffer_data +/****d* silcutil/SilcBufferAPI/silc_buffer_headlen * * NAME * - * unsigned char *silc_buffer_data(SilcBuffer sb) + * SilcUInt32 silc_buffer_headlen(SilcBuffer sb) * * DESCRIPTION * - * Returns pointer to the data area of the buffer. + * Returns the current length of the head data area of the buffer. * - * SOURCE - */ -#define silc_buffer_data(x) (x)->data -/***/ + ***/ +static inline +SilcUInt32 silc_buffer_headlen(SilcBuffer x) +{ + return (SilcUInt32)(x->data - x->head); +} -/* Inline functions */ +/****d* silcutil/SilcBufferAPI/silc_buffer_taillen + * + * NAME + * + * SilcUInt32 silc_buffer_taillen(SilcBuffer sb) + * + * DESCRIPTION + * + * Returns the current length of the tail data area of the buffer. + * + ***/ +static inline +SilcUInt32 silc_buffer_taillen(SilcBuffer x) +{ + return (SilcUInt32)(x->end - x->tail); +} /****f* silcutil/SilcBufferAPI/silc_buffer_alloc * @@ -214,13 +249,13 @@ SilcBuffer silc_buffer_alloc(SilcUInt32 len) /* Allocate new SilcBuffer */ sb = (SilcBuffer)silc_calloc(1, sizeof(*sb)); - if (!sb) + if (silc_unlikely(!sb)) return NULL; - if (len) { + if (silc_likely(len)) { /* Allocate the actual data area */ sb->head = (unsigned char *)silc_calloc(len, sizeof(*sb->head)); - if (!sb->head) + if (silc_unlikely(!sb->head)) return NULL; /* Set pointers to the new buffer */ @@ -243,6 +278,11 @@ SilcBuffer silc_buffer_alloc(SilcUInt32 len) * * Frees SilcBuffer. Can be called safely `sb' as NULL. * + * NOTES + * + * Must not be called for buffers allocated with silc_buffer_salloc, + * silc_buffer_salloc_size, silc_buffer_scopy and silc_buffer_sclone. + * ***/ static inline @@ -286,6 +326,32 @@ unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len) return buf; } +/****f* silcutil/SilcBufferAPI/silc_buffer_purge + * + * SYNOPSIS + * + * static inline + * void silc_buffer_purge(SilcBuffer sb); + * + * DESCRIPTION + * + * Same as silc_buffer_free but free's only the contents of the buffer + * not the buffer itself. The `sb' remains intact, data is freed. Buffer + * is ready for re-use after calling this function. + * + * NOTES + * + * Must not be called for buffers allocated with silc_buffer_salloc, + * silc_buffer_salloc_size, silc_buffer_scopy and silc_buffer_sclone. + * + ***/ + +static inline +void silc_buffer_purge(SilcBuffer sb) +{ + silc_free(silc_buffer_steal(sb, NULL)); +} + /****f* silcutil/SilcBufferAPI/silc_buffer_set * * SYNOPSIS @@ -351,9 +417,9 @@ unsigned char *silc_buffer_pull(SilcBuffer sb, SilcUInt32 len) { unsigned char *old_data = sb->data; #if defined(SILC_DEBUG) - assert(len <= silc_buffer_len(sb)); + SILC_ASSERT(len <= silc_buffer_len(sb)); #else - if (len > silc_buffer_len(sb)) + if (silc_unlikely(len > silc_buffer_len(sb))) return NULL; #endif sb->data += len; @@ -395,9 +461,9 @@ unsigned char *silc_buffer_push(SilcBuffer sb, SilcUInt32 len) { unsigned char *old_data = sb->data; #if defined(SILC_DEBUG) - assert((sb->data - len) >= sb->head); + SILC_ASSERT((sb->data - len) >= sb->head); #else - if ((sb->data - len) < sb->head) + if (silc_unlikely((sb->data - len) < sb->head)) return NULL; #endif sb->data -= len; @@ -439,9 +505,9 @@ unsigned char *silc_buffer_pull_tail(SilcBuffer sb, SilcUInt32 len) { unsigned char *old_tail = sb->tail; #if defined(SILC_DEBUG) - assert(len <= silc_buffer_taillen(sb)); + SILC_ASSERT(len <= silc_buffer_taillen(sb)); #else - if (len > silc_buffer_taillen(sb)) + if (silc_unlikely(len > silc_buffer_taillen(sb))) return NULL; #endif sb->tail += len; @@ -483,9 +549,9 @@ unsigned char *silc_buffer_push_tail(SilcBuffer sb, SilcUInt32 len) { unsigned char *old_tail = sb->tail; #if defined(SILC_DEBUG) - assert((sb->tail - len) >= sb->data); + SILC_ASSERT((sb->tail - len) >= sb->data); #else - if ((sb->tail - len) < sb->data) + if (silc_unlikely((sb->tail - len) < sb->data)) return NULL; #endif sb->tail -= len; @@ -524,9 +590,9 @@ unsigned char *silc_buffer_put_head(SilcBuffer sb, SilcUInt32 len) { #if defined(SILC_DEBUG) - assert(len <= silc_buffer_headlen(sb)); + SILC_ASSERT(len <= silc_buffer_headlen(sb)); #else - if (len > silc_buffer_headlen(sb)) + if (silc_unlikely(len > silc_buffer_headlen(sb))) return NULL; #endif return (unsigned char *)memcpy(sb->head, data, len); @@ -564,9 +630,9 @@ unsigned char *silc_buffer_put(SilcBuffer sb, SilcUInt32 len) { #if defined(SILC_DEBUG) - assert(len <= silc_buffer_len(sb)); + SILC_ASSERT(len <= silc_buffer_len(sb)); #else - if (len > silc_buffer_len(sb)) + if (silc_unlikely(len > silc_buffer_len(sb))) return NULL; #endif return (unsigned char *)memcpy(sb->data, data, len); @@ -604,9 +670,9 @@ unsigned char *silc_buffer_put_tail(SilcBuffer sb, SilcUInt32 len) { #if defined(SILC_DEBUG) - assert(len <= silc_buffer_taillen(sb)); + SILC_ASSERT(len <= silc_buffer_taillen(sb)); #else - if (len > silc_buffer_taillen(sb)) + if (silc_unlikely(len > silc_buffer_taillen(sb))) return NULL; #endif return (unsigned char *)memcpy(sb->tail, data, len); @@ -631,7 +697,7 @@ static inline SilcBuffer silc_buffer_alloc_size(SilcUInt32 len) { SilcBuffer sb = silc_buffer_alloc(len); - if (!sb) + if (silc_unlikely(!sb)) return NULL; silc_buffer_pull_tail(sb, len); return sb; @@ -679,6 +745,48 @@ void silc_buffer_clear(SilcBuffer sb) silc_buffer_reset(sb); } +/****f* silcutil/SilcBufferAPI/silc_buffer_start + * + * SYNOPSIS + * + * static inline + * void silc_buffer_start(SilcBuffer sb); + * + * DESCRIPTION + * + * Moves the data area at the start of the buffer. The tail area remains + * as is. + * + ***/ + +static inline +void silc_buffer_start(SilcBuffer sb) +{ + sb->data = sb->head; +} + +/****f* silcutil/SilcBufferAPI/silc_buffer_end + * + * SYNOPSIS + * + * static inline + * void silc_buffer_end(SilcBuffer sb); + * + * DESCRIPTION + * + * Moves the end of the data area to the end of the buffer. The start + * of the data area remains same. If the start of data area is at the + * start of the buffer, after this function returns the buffer's data + * area length is the length of the entire buffer. + * + ***/ + +static inline +void silc_buffer_end(SilcBuffer sb) +{ + sb->tail = sb->end; +} + /****f* silcutil/SilcBufferAPI/silc_buffer_copy * * SYNOPSIS @@ -700,7 +808,7 @@ SilcBuffer silc_buffer_copy(SilcBuffer sb) SilcBuffer sb_new; sb_new = silc_buffer_alloc_size(silc_buffer_len(sb)); - if (!sb_new) + if (silc_unlikely(!sb_new)) return NULL; silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb)); @@ -728,7 +836,7 @@ SilcBuffer silc_buffer_clone(SilcBuffer sb) SilcBuffer sb_new; sb_new = silc_buffer_alloc_size(silc_buffer_truelen(sb)); - if (!sb_new) + if (silc_unlikely(!sb_new)) return NULL; silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb)); sb_new->data = sb_new->head + silc_buffer_headlen(sb); @@ -762,13 +870,13 @@ SilcBuffer silc_buffer_realloc(SilcBuffer sb, SilcUInt32 newsize) if (!sb) return silc_buffer_alloc(newsize); - if (newsize <= silc_buffer_truelen(sb)) + if (silc_unlikely(newsize <= silc_buffer_truelen(sb))) return sb; hlen = silc_buffer_headlen(sb); dlen = silc_buffer_len(sb); h = (unsigned char *)silc_realloc(sb->head, newsize); - if (!h) + if (silc_unlikely(!h)) return NULL; sb->head = h; sb->data = sb->head + hlen; @@ -797,12 +905,45 @@ static inline SilcBuffer silc_buffer_realloc_size(SilcBuffer sb, SilcUInt32 newsize) { sb = silc_buffer_realloc(sb, newsize); - if (!sb) + if (silc_unlikely(!sb)) return NULL; silc_buffer_pull_tail(sb, silc_buffer_taillen(sb)); return sb; } +/****f* silcutil/SilcBufferAPI/silc_buffer_enlarge + * + * SYNOPSIS + * + * static inline + * SilcBuffer silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size); + * + * DESCRIPTION + * + * Enlarges the buffer by the amount of `size' if it doesn't have that + * must space in the data area and in the tail area. Moves the tail + * area automatically after enlarging so that the current data area + * is at least the size of `size'. If there is more space than `size' + * in the data area this does not do anything. If there is enough + * space in the tail area this merely moves the tail area to reveal + * the extra space. Returns FALSE on error. + * + ***/ + +static inline +SilcBool silc_buffer_enlarge(SilcBuffer sb, SilcUInt32 size) +{ + if (size > silc_buffer_len(sb)) { + if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb)) + if (silc_unlikely(!silc_buffer_realloc(sb, silc_buffer_truelen(sb) + + (size - silc_buffer_taillen(sb) - + silc_buffer_len(sb))))) + return FALSE; + silc_buffer_pull_tail(sb, size - silc_buffer_len(sb)); + } + return TRUE; +} + /* SilcStack aware SilcBuffer routines */ @@ -832,12 +973,12 @@ SilcBuffer silc_buffer_salloc(SilcStack stack, SilcUInt32 len) /* Allocate new SilcBuffer */ sb = (SilcBuffer)silc_scalloc(stack, 1, sizeof(*sb)); - if (!sb) + if (silc_unlikely(!sb)) return NULL; /* Allocate the actual data area */ - sb->head = (unsigned char *)silc_smalloc_ua(stack, len); - if (!sb->head) + sb->head = (unsigned char *)silc_smalloc(stack, len); + if (silc_unlikely(!sb->head)) return NULL; /* Set pointers to the new buffer */ @@ -870,7 +1011,7 @@ static inline SilcBuffer silc_buffer_salloc_size(SilcStack stack, SilcUInt32 len) { SilcBuffer sb = silc_buffer_salloc(stack, len); - if (!sb) + if (silc_unlikely(!sb)) return NULL; silc_buffer_pull_tail(sb, len); return sb; @@ -913,13 +1054,13 @@ SilcBuffer silc_buffer_srealloc(SilcStack stack, hlen = silc_buffer_headlen(sb); dlen = silc_buffer_len(sb); - h = (unsigned char *)silc_srealloc_ua(stack, silc_buffer_truelen(sb), - sb->head, newsize); + h = (unsigned char *)silc_srealloc(stack, silc_buffer_truelen(sb), + sb->head, newsize); if (!h) { /* Do slow and stack wasting realloc. The old sb->head is lost and is freed eventually. */ - h = silc_smalloc_ua(stack, newsize); - if (!h) + h = (unsigned char *)silc_smalloc(stack, newsize); + if (silc_unlikely(!h)) return NULL; memcpy(h, sb->head, silc_buffer_truelen(sb)); } @@ -956,12 +1097,50 @@ SilcBuffer silc_buffer_srealloc_size(SilcStack stack, SilcBuffer sb, SilcUInt32 newsize) { sb = silc_buffer_srealloc(stack, sb, newsize); - if (!sb) + if (silc_unlikely(!sb)) return NULL; silc_buffer_pull_tail(sb, silc_buffer_taillen(sb)); return sb; } +/****f* silcutil/SilcBufferAPI/silc_buffer_senlarge + * + * SYNOPSIS + * + * static inline + * SilcBuffer silc_buffer_senlarge(SilcStack stack, SilcBuffer sb, + * SilcUInt32 size); + * + * DESCRIPTION + * + * Enlarges the buffer by the amount of `size' if it doesn't have that + * must space in the data area and in the tail area. Moves the tail + * area automatically after enlarging so that the current data area + * is at least the size of `size'. If there is more space than `size' + * in the data area this does not do anything. If there is enough + * space in the tail area this merely moves the tail area to reveal + * the extra space. Returns FALSE on error. + * + * This routine use SilcStack are memory source. If `stack' is NULL + * reverts back to normal allocating routine. + * + ***/ + +static inline +SilcBool silc_buffer_senlarge(SilcStack stack, SilcBuffer sb, SilcUInt32 size) +{ + if (size > silc_buffer_len(sb)) { + if (size > silc_buffer_taillen(sb) + silc_buffer_len(sb)) + if (silc_unlikely(!silc_buffer_srealloc(stack, sb, + silc_buffer_truelen(sb) + + (size - silc_buffer_taillen(sb) - + silc_buffer_len(sb))))) + return FALSE; + silc_buffer_pull_tail(sb, size - silc_buffer_len(sb)); + } + return TRUE; +} + /****f* silcutil/SilcBufferAPI/silc_buffer_scopy * * SYNOPSIS @@ -986,7 +1165,7 @@ SilcBuffer silc_buffer_scopy(SilcStack stack, SilcBuffer sb) SilcBuffer sb_new; sb_new = silc_buffer_salloc_size(stack, silc_buffer_len(sb)); - if (!sb_new) + if (silc_unlikely(!sb_new)) return NULL; silc_buffer_put(sb_new, sb->data, silc_buffer_len(sb)); @@ -1017,7 +1196,7 @@ SilcBuffer silc_buffer_sclone(SilcStack stack, SilcBuffer sb) SilcBuffer sb_new; sb_new = silc_buffer_salloc_size(stack, silc_buffer_truelen(sb)); - if (!sb_new) + if (silc_unlikely(!sb_new)) return NULL; silc_buffer_put(sb_new, sb->head, silc_buffer_truelen(sb)); sb_new->data = sb_new->head + silc_buffer_headlen(sb);