Merged silc_1_1_branch to trunk.
[silc.git] / lib / silcutil / silcbuffer.h
index 644085025d6c5e7500bd19dd58eab0f2bfce216f..5ce671175b628994820e5edd63a20efb026cb504 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  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
  *     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,106 +120,114 @@ typedef struct {
 
 /* Macros */
 
-/****d* silcutil/SilcBufferAPI/silc_buffer_truelen
+/****f* silcutil/SilcBufferAPI/silc_buffer_data
  *
  * NAME
  *
- *    SilcUInt32 silc_buffer_truelen(SilcBuffer sb)
+ *    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
  *
- *    SilcUInt32 silc_buffer_len(SilcBuffer sb)
+ *    #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
  *
- *    SilcUInt32 silc_buffer_headlen(SilcBuffer sb)
+ *    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
  *
- *    SilcUInt32 silc_buffer_taillen(SilcBuffer sb)
+ *    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);
+}
 
-/****f* silcutil/SilcBufferAPI/silc_buffer_datalen
+/****d* silcutil/SilcBufferAPI/silc_buffer_taillen
  *
  * NAME
  *
- *    #define silc_buffer_datalen ...
+ *    SilcUInt32 silc_buffer_taillen(SilcBuffer sb)
  *
  * DESCRIPTION
  *
- *    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));
+ *    Returns the current length of the tail data area of the buffer.
  *
- * SOURCE
- */
-#define silc_buffer_datalen(x) (x) ? silc_buffer_data(x) : NULL, \
-  (x) ? silc_buffer_len(x) : 0
-/***/
-
-/* Inline functions */
+ ***/
+static inline
+SilcUInt32 silc_buffer_taillen(SilcBuffer x)
+{
+  return (SilcUInt32)(x->end - x->tail);
+}
 
 /****f* silcutil/SilcBufferAPI/silc_buffer_alloc
  *
@@ -238,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 */
@@ -267,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
@@ -323,6 +339,11 @@ unsigned char *silc_buffer_steal(SilcBuffer sb, SilcUInt32 *data_len)
  *    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
@@ -396,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;
@@ -440,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;
@@ -484,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;
@@ -528,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;
@@ -569,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);
@@ -609,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);
@@ -649,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);
@@ -676,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;
@@ -724,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
@@ -745,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));
 
@@ -773,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);
@@ -807,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;
@@ -842,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 */
 
@@ -877,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 */
@@ -915,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;
@@ -958,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));
   }
@@ -1001,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
@@ -1031,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));
 
@@ -1062,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);