summaryrefslogtreecommitdiffstats
path: root/src/H5RS.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5RS.c')
-rw-r--r--src/H5RS.c481
1 files changed, 375 insertions, 106 deletions
diff --git a/src/H5RS.c b/src/H5RS.c
index 0e8ab27..6ab5334 100644
--- a/src/H5RS.c
+++ b/src/H5RS.c
@@ -15,9 +15,16 @@
* Reference counted string algorithms.
*
* These are used for various internal strings which get copied multiple times.
+ * They also efficiently handle dynamically allocations and appends.
*
*/
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5RSmodule.h" /* This source code file is part of the H5RS module */
+
/***********/
/* Headers */
/***********/
@@ -30,6 +37,9 @@
/* Local Macros */
/****************/
+/* Initial buffer size to allocate */
+#define H5RS_ALLOC_SIZE 256
+
/******************/
/* Local Typedefs */
/******************/
@@ -37,7 +47,10 @@
/* Private typedefs & structs */
struct H5RS_str_t {
char * s; /* String to be reference counted */
- unsigned wrapped; /* Indicates that the string to be ref-counted is not copied */
+ char * end; /* Pointer to terminating NUL character at the end of the string */
+ size_t len; /* Current length of the string */
+ size_t max; /* Size of allocated buffer */
+ hbool_t wrapped; /* Indicates that the string to be ref-counted is not copied */
unsigned n; /* Reference count of number of pointers sharing string */
};
@@ -48,10 +61,17 @@ struct H5RS_str_t {
/********************/
/* Local Prototypes */
/********************/
+static herr_t H5RS__xstrdup(H5RS_str_t *rs, const char *s);
+static herr_t H5RS__prepare_for_append(H5RS_str_t *rs);
+static herr_t H5RS__resize_for_append(H5RS_str_t *rs, size_t len);
+
/*********************/
/* Package Variables */
/*********************/
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
/*****************************/
/* Library Private Variables */
/*****************************/
@@ -64,7 +84,7 @@ struct H5RS_str_t {
H5FL_DEFINE_STATIC(H5RS_str_t);
/* Declare the PQ free list for the wrapped strings */
-H5FL_BLK_DEFINE(str_buf);
+H5FL_BLK_DEFINE_STATIC(str_buf);
/*--------------------------------------------------------------------------
NAME
@@ -72,11 +92,12 @@ H5FL_BLK_DEFINE(str_buf);
PURPOSE
Duplicate the string being reference counted
USAGE
- char *H5RS__xstrdup(s)
+ herr_t H5RS__xstrdup(rs, s)
+ H5RS_str_t *rs; IN/OUT: Ref-counted string to hold duplicated string
const char *s; IN: String to duplicate
RETURNS
- Returns a pointer to a new string on success, NULL on failure.
+ Non-negative on success/Negative on failure
DESCRIPTION
Duplicate a string buffer being reference counted. Use this instead of
[H5MM_][x]strdup, in order to use the free-list memory routines.
@@ -85,28 +106,148 @@ H5FL_BLK_DEFINE(str_buf);
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
-static char *
-H5RS__xstrdup(const char *s)
+static herr_t
+H5RS__xstrdup(H5RS_str_t *rs, const char *s)
{
- char *ret_value; /* Return value */
+ herr_t ret_value = SUCCEED; /* Return value */
- FUNC_ENTER_STATIC_NOERR
+ FUNC_ENTER_STATIC
- if (s) {
- size_t len = HDstrlen(s) + 1;
+ /* Sanity check */
+ HDassert(rs);
- ret_value = (char *)H5FL_BLK_MALLOC(str_buf, len);
- HDassert(ret_value);
- HDstrncpy(ret_value, s, len);
+ if (s) {
+ size_t len = HDstrlen(s);
+
+ /* Determine size of buffer to allocate */
+ rs->max = H5RS_ALLOC_SIZE;
+ while ((len + 1) > rs->max)
+ rs->max *= 2;
+
+ /* Allocate the underlying string */
+ if (NULL == (rs->s = (char *)H5FL_BLK_MALLOC(str_buf, rs->max)))
+ HGOTO_ERROR(H5E_RS, H5E_CANTALLOC, FAIL, "memory allocation failed")
+ if (len)
+ HDmemcpy(rs->s, s, len);
+ rs->end = rs->s + len;
+ *rs->end = '\0';
+ rs->len = len;
} /* end if */
- else
- ret_value = NULL;
+ else {
+ /* Free previous string, if one */
+ if (rs->s) {
+ H5FL_BLK_FREE(str_buf, rs->s);
+ rs->s = rs->end = NULL;
+ rs->max = rs->len = 0;
+ } /* end if */
+ else {
+ /* Sanity checks */
+ HDassert(NULL == rs->end);
+ HDassert(0 == rs->max);
+ HDassert(0 == rs->len);
+ } /* end else */
+ } /* end else */
+done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5RS__xstrdup() */
/*--------------------------------------------------------------------------
NAME
+ H5RS__prepare_for_append
+ PURPOSE
+ Prepare a ref-counted string for an append
+ USAGE
+ herr_t H5RS__prepare_for_append(rs)
+ H5RS_str_t *rs; IN/OUT: Ref-counted string to hold duplicated string
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Allocate space for a string, or duplicate a wrapped string, in preparation
+ for appending another string.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5RS__prepare_for_append(H5RS_str_t *rs)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(rs);
+
+ if (NULL == rs->s) {
+ rs->max = H5RS_ALLOC_SIZE;
+ if (NULL == (rs->s = (char *)H5FL_BLK_MALLOC(str_buf, rs->max)))
+ HGOTO_ERROR(H5E_RS, H5E_CANTALLOC, FAIL, "memory allocation failed")
+ rs->end = rs->s;
+ *rs->s = '\0';
+ rs->len = 0;
+ } /* end if */
+ else {
+ /* If the ref-counted string started life as a wrapper around an
+ * existing string, duplicate the string now, so we can modify it.
+ */
+ if (rs->wrapped) {
+ if (H5RS__xstrdup(rs, rs->s) < 0)
+ HGOTO_ERROR(H5E_RS, H5E_CANTCOPY, FAIL, "can't copy string")
+ rs->wrapped = FALSE;
+ } /* end if */
+ } /* end else */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5RS__prepare_for_append() */
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5RS__resize_for_append
+ PURPOSE
+ Resize ref-counted string buffer to accommodate appending another string
+ USAGE
+ herr_t H5RS__resize_for_append(rs, len)
+ H5RS_str_t *rs; IN/OUT: Ref-counted string to hold duplicated string
+ size_t len; IN: Additional length to accommodate
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Resize a ref-counted string buffer to be large enough to accommodate
+ another string of a specified length.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5RS__resize_for_append(H5RS_str_t *rs, size_t len)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(rs);
+
+ /* Check if buffer should be re-allocated */
+ if (len >= (rs->max - rs->len)) {
+ /* Allocate a large enough buffer */
+ while (len >= (rs->max - rs->len))
+ rs->max *= 2;
+ if (NULL == (rs->s = (char *)H5FL_BLK_REALLOC(str_buf, rs->s, rs->max)))
+ HGOTO_ERROR(H5E_RS, H5E_CANTALLOC, FAIL, "memory allocation failed")
+ rs->end = rs->s + rs->len;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5RS__resize() */
+
+/*--------------------------------------------------------------------------
+ NAME
H5RS_create
PURPOSE
Create a reference counted string
@@ -127,18 +268,19 @@ H5RS__xstrdup(const char *s)
H5RS_str_t *
H5RS_create(const char *s)
{
- H5RS_str_t *ret_value; /* Return value */
+ H5RS_str_t *ret_value = NULL; /* Return value */
FUNC_ENTER_NOAPI(NULL)
/* Allocate ref-counted string structure */
- if (NULL == (ret_value = H5FL_MALLOC(H5RS_str_t)))
- HGOTO_ERROR(H5E_RS, H5E_NOSPACE, NULL, "memory allocation failed")
+ if (NULL == (ret_value = H5FL_CALLOC(H5RS_str_t)))
+ HGOTO_ERROR(H5E_RS, H5E_CANTALLOC, NULL, "memory allocation failed")
/* Set the internal fields */
- ret_value->s = H5RS__xstrdup(s);
- ret_value->wrapped = 0;
- ret_value->n = 1;
+ if (s)
+ if (H5RS__xstrdup(ret_value, s) < 0)
+ HGOTO_ERROR(H5E_RS, H5E_CANTCOPY, NULL, "can't copy string")
+ ret_value->n = 1;
done:
FUNC_LEAVE_NOAPI(ret_value)
@@ -175,54 +317,224 @@ H5RS_wrap(const char *s)
HGOTO_ERROR(H5E_RS, H5E_CANTALLOC, NULL, "memory allocation failed")
/* Set the internal fields */
- ret_value->s = (char *)s;
- ret_value->wrapped = 1;
+ ret_value->s = (char *)s;
+ ret_value->len = HDstrlen(s);
+ ret_value->end = ret_value->s + ret_value->len;
+
+ ret_value->wrapped = TRUE;
+ ret_value->max = 0; /* Wrapped, not allocated */
ret_value->n = 1;
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5RS_wrap() */
-/*--------------------------------------------------------------------------
- NAME
- H5RS_own
- PURPOSE
- Transfer ownership of a regular string to a reference counted string
- USAGE
- H5RS_str_t *H5RS_own(s)
- const char *s; IN: String to transfer ownership of
+/*-------------------------------------------------------------------------
+ * Function: H5RS_asprintf_cat
+ *
+ * Purpose: This function appends formatted output to a ref-counted string,
+ * allocating the managed string if necessary. The formatting
+ * string is printf() compatible.
+ *
+ * Return: SUCCEED / FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Friday, September 18, 2020
+ *
+ *-------------------------------------------------------------------------
+ */
+/* Disable warning for "format not a string literal" here -QAK */
+/*
+ * This pragma only needs to surround the sprintf() calls with
+ * format_templ in the code below, but early (4.4.7, at least) gcc only
+ * allows diagnostic pragmas to be toggled outside of functions.
+ */
+H5_GCC_DIAG_OFF("format-nonliteral")
+H5_ATTR_FORMAT(printf, 2, 3)
+herr_t
+H5RS_asprintf_cat(H5RS_str_t *rs, const char *fmt, ...)
+{
+ va_list args1, args2;
+ size_t out_len;
+ herr_t ret_value = SUCCEED; /* Return value */
- RETURNS
- Returns a pointer to a new ref-counted string on success, NULL on failure.
- DESCRIPTION
- Transfer ownership of a dynamically allocated string to a reference counted
- string. The routine which passed in the string should not attempt to free
- it, the reference counting string routines will do that when the reference
- count drops to zero.
- GLOBAL VARIABLES
- COMMENTS, BUGS, ASSUMPTIONS
- EXAMPLES
- REVISION LOG
---------------------------------------------------------------------------*/
-H5RS_str_t *
-H5RS_own(char *s)
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(rs);
+ HDassert(fmt);
+
+ /* Prepare the [possibly wrapped or empty] ref-counted string for an append */
+ if (H5RS__prepare_for_append(rs) < 0)
+ HGOTO_ERROR(H5E_RS, H5E_CANTINIT, FAIL, "can't initialize ref-counted string")
+
+ /* Attempt to write formatted output into the managed string */
+ HDva_start(args1, fmt);
+ HDva_copy(args2, args1);
+ while ((out_len = (size_t)HDvsnprintf(rs->end, (rs->max - rs->len), fmt, args1)) >= (rs->max - rs->len)) {
+ /* Allocate a large enough buffer */
+ if (H5RS__resize_for_append(rs, out_len) < 0)
+ HGOTO_ERROR(H5E_RS, H5E_CANTRESIZE, FAIL, "can't resize ref-counted string buffer")
+
+ /* Restart the va_list */
+ HDva_end(args1);
+ HDva_copy(args1, args2);
+ } /* end while */
+
+ /* Increment the size & end of the string */
+ rs->len += out_len;
+ rs->end += out_len;
+
+ /* Finish access to varargs */
+ HDva_end(args1);
+ HDva_end(args2);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5RS_asprintf_cat() */
+H5_GCC_DIAG_ON("format-nonliteral")
+
+/*-------------------------------------------------------------------------
+ * Function: H5RS_acat
+ *
+ * Purpose: This function appends a character string to a ref-counted string,
+ * allocating the managed string if necessary.
+ *
+ * Return: SUCCEED / FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Friday, September 18, 2020
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5RS_acat(H5RS_str_t *rs, const char *s)
{
- H5RS_str_t *ret_value; /* Return value */
+ herr_t ret_value = SUCCEED; /* Return value */
- FUNC_ENTER_NOAPI(NULL)
+ FUNC_ENTER_NOAPI(FAIL)
- /* Allocate ref-counted string structure */
- if (NULL == (ret_value = H5FL_MALLOC(H5RS_str_t)))
- HGOTO_ERROR(H5E_RS, H5E_NOSPACE, NULL, "memory allocation failed")
+ /* Sanity checks */
+ HDassert(rs);
+ HDassert(s);
- /* Set the internal fields */
- ret_value->s = s;
- ret_value->wrapped = 0;
- ret_value->n = 1;
+ /* Concatenate the provided string on to the managed string */
+ if (*s) {
+ size_t len = HDstrlen(s);
+
+ /* Allocate the underlying string, if necessary */
+ if (H5RS__prepare_for_append(rs) < 0)
+ HGOTO_ERROR(H5E_RS, H5E_CANTINIT, FAIL, "can't initialize ref-counted string")
+
+ /* Increase the managed string's buffer size if necessary */
+ if ((rs->len + len) >= rs->max)
+ if (H5RS__resize_for_append(rs, len) < 0)
+ HGOTO_ERROR(H5E_RS, H5E_CANTRESIZE, FAIL, "can't resize ref-counted string buffer")
+
+ /* Append the string */
+ HDmemcpy(rs->end, s, len);
+ rs->end += len;
+ *rs->end = '\0';
+ rs->len += len;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5RS_acat() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5RS_ancat
+ *
+ * Purpose: This function appends at most 'n' characters from a string
+ * to a ref-counted string, allocating the managed string if
+ * necessary.
+ *
+ * Return: SUCCEED / FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Friday, September 18, 2020
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5RS_ancat(H5RS_str_t *rs, const char *s, size_t n)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(rs);
+ HDassert(s);
+
+ /* Concatenate the provided string on to the managed string */
+ if (n && *s) {
+ size_t len = HDstrlen(s);
+
+ /* Limit characters to copy to the minimum of 'n' and 'len' */
+ n = MIN(len, n);
+
+ /* Allocate the underlying string, if necessary */
+ if (H5RS__prepare_for_append(rs) < 0)
+ HGOTO_ERROR(H5E_RS, H5E_CANTINIT, FAIL, "can't initialize ref-counted string")
+
+ /* Increase the managed string's buffer size if necessary */
+ if ((rs->len + n) >= rs->max)
+ if (H5RS__resize_for_append(rs, n) < 0)
+ HGOTO_ERROR(H5E_RS, H5E_CANTRESIZE, FAIL, "can't resize ref-counted string buffer")
+
+ /* Append the string */
+ HDmemcpy(rs->end, s, n);
+ rs->end += n;
+ *rs->end = '\0';
+ rs->len += n;
+ } /* end if */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5RS_ancat() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5RS_aputc
+ *
+ * Purpose: This function appends a character to a ref-counted string,
+ * allocating the managed string if necessary.
+ *
+ * Return: SUCCEED / FAIL
+ *
+ * Programmer: Quincey Koziol
+ * Friday, September 18, 2020
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5RS_aputc(H5RS_str_t *rs, int c)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity checks */
+ HDassert(rs);
+ HDassert(c);
+
+ /* Allocate the underlying string, if necessary */
+ if (H5RS__prepare_for_append(rs) < 0)
+ HGOTO_ERROR(H5E_RS, H5E_CANTINIT, FAIL, "can't initialize ref-counted string")
+
+ /* Increase the managed string's buffer size if necessary */
+ if ((rs->len + 1) >= rs->max)
+ if (H5RS__resize_for_append(rs, 1) < 0)
+ HGOTO_ERROR(H5E_RS, H5E_CANTRESIZE, FAIL, "can't resize ref-counted string buffer")
+
+ /* Append the current character */
+ *rs->end++ = (char)c;
+ rs->len++;
+ *rs->end = '\0';
done:
FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5RS_own() */
+} /* end H5RS_aputc() */
/*--------------------------------------------------------------------------
NAME
@@ -283,7 +595,9 @@ H5RS_decr(H5RS_str_t *rs)
herr_t
H5RS_incr(H5RS_str_t *rs)
{
- FUNC_ENTER_NOAPI_NOINIT_NOERR
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
/* Sanity check */
HDassert(rs);
@@ -294,14 +608,16 @@ H5RS_incr(H5RS_str_t *rs)
* scope appropriately.
*/
if (rs->wrapped) {
- rs->s = H5RS__xstrdup(rs->s);
- rs->wrapped = 0;
+ if (H5RS__xstrdup(rs, rs->s) < 0)
+ HGOTO_ERROR(H5E_RS, H5E_CANTCOPY, FAIL, "can't copy string")
+ rs->wrapped = FALSE;
} /* end if */
/* Increment reference count for string */
rs->n++;
- FUNC_LEAVE_NOAPI(SUCCEED)
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
} /* end H5RS_incr() */
/*--------------------------------------------------------------------------
@@ -338,53 +654,6 @@ H5RS_dup(H5RS_str_t *ret_value)
/*--------------------------------------------------------------------------
NAME
- H5RS_dup_str
- PURPOSE
- "Duplicate" a regular string into a ref-counted string
- USAGE
- H5RS_str_t H5RS_dup_str(s)
- const char *s; IN: Regular string to duplicate
-
- RETURNS
- Returns a pointer to ref-counted string on success, NULL on failure.
- DESCRIPTION
- Duplicate a regular string into a ref-counted string.
- GLOBAL VARIABLES
- COMMENTS, BUGS, ASSUMPTIONS
- EXAMPLES
- REVISION LOG
---------------------------------------------------------------------------*/
-H5RS_str_t *
-H5RS_dup_str(const char *s)
-{
- char * new_str; /* Duplicate of string */
- size_t path_len; /* Length of the path */
- H5RS_str_t *ret_value;
-
- FUNC_ENTER_NOAPI(NULL)
-
- /* Sanity check */
- HDassert(s);
-
- /* Get the length of the string */
- path_len = HDstrlen(s);
-
- /* Allocate space for the string */
- if (NULL == (new_str = (char *)H5FL_BLK_MALLOC(str_buf, path_len + 1)))
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
-
- /* Copy name for full path */
- HDstrncpy(new_str, s, (path_len + 1));
-
- /* Create reference counted string for path */
- ret_value = H5RS_own(new_str);
-
-done:
- FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5RS_dup_str() */
-
-/*--------------------------------------------------------------------------
- NAME
H5RS_cmp
PURPOSE
Compare two ref-counted strings