Skip to content
Snippets Groups Projects
Commit aa25d10a authored by Joseph Schuchart's avatar Joseph Schuchart
Browse files

Add opal_cstring_t, a reference-counted constant string object

parent 96fce243
Branches
No related tags found
No related merge requests found
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
# Source code files # Source code files
headers += \ headers += \
class/opal_bitmap.h \ class/opal_bitmap.h \
class/opal_cstring.h \
class/opal_free_list.h \ class/opal_free_list.h \
class/opal_hash_table.h \ class/opal_hash_table.h \
class/opal_hotel.h \ class/opal_hotel.h \
...@@ -43,6 +44,7 @@ headers += \ ...@@ -43,6 +44,7 @@ headers += \
lib@OPAL_LIB_PREFIX@open_pal_la_SOURCES += \ lib@OPAL_LIB_PREFIX@open_pal_la_SOURCES += \
class/opal_bitmap.c \ class/opal_bitmap.c \
class/opal_cstring.c \
class/opal_free_list.c \ class/opal_free_list.c \
class/opal_hash_table.c \ class/opal_hash_table.c \
class/opal_hotel.c \ class/opal_hotel.c \
......
/*
* Copyright (c) 2020 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2020 High Performance Computing Center Stuttgart,
* University of Stuttgart. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "opal_cstring.h"
#include <errno.h>
#include <ctype.h>
#include <stddef.h>
#include "opal/constants.h"
#include "opal/util/string_copy.h"
static void opal_cstring_ctor(opal_cstring_t *obj);
OBJ_CLASS_INSTANCE(
opal_cstring_t,
opal_object_t,
&opal_cstring_ctor,
NULL
);
/* make sure we have sufficient padding to always null-terminate the string */
#if (__STDC_VERSION__ >= 201112L)
_Static_assert(sizeof(opal_cstring_t) > offsetof(opal_cstring_t, string),
"Insufficient padding available in opal_cstring_t");
#endif // (__STDC_VERSION__ >= 201112L)
static void opal_cstring_ctor(opal_cstring_t *obj)
{
*(size_t*)&(obj->length) = 0;
/* make sure the string is null-terminated */
((char*)obj->string)[0] = '\n';
}
static inline size_t opal_cstring_alloc_size(size_t len)
{
/* the size required for the object and the string, incl. the null-terminator */
size_t res = sizeof(opal_cstring_t) + len + 1;
/* adjust for the additional padding that is used for the string anyway */
res -= (sizeof(opal_cstring_t) - offsetof(opal_cstring_t, string));
/* make sure we allocate at least sizeof(opal_cstring_t) */
return (res > sizeof(opal_cstring_t)) ? res : sizeof(opal_cstring_t);
}
opal_cstring_t* opal_cstring_create_l(const char *string, size_t len)
{
if (NULL == string || 0 == len) {
return OBJ_NEW(opal_cstring_t);
}
/* Allocate space for the object, the characters in \c string and the terminating null */
opal_cstring_t* res = (opal_cstring_t*)malloc(opal_cstring_alloc_size(len));
if (NULL == res) {
return NULL;
}
OBJ_CONSTRUCT(res, opal_cstring_t);
/* cast away const for setting the member values */
*(size_t*)&(res->length) = len;
opal_string_copy((char*)res->string, string, len+1);
return res;
}
opal_cstring_t* opal_cstring_create(const char *string)
{
if (NULL == string) {
return OBJ_NEW(opal_cstring_t);
}
size_t len = strlen(string);
return opal_cstring_create_l(string, len);
}
int opal_cstring_to_int(opal_cstring_t *string, int *interp)
{
long tmp;
char *endp;
if (NULL == string || '\0' == string->string[0]) {
return OPAL_ERR_BAD_PARAM;
}
errno = 0;
tmp = strtol(string->string, &endp, 10);
/* we found something not a number */
if (*endp != '\0') return OPAL_ERR_BAD_PARAM;
/* underflow */
if (tmp == 0 && errno == EINVAL) return OPAL_ERR_BAD_PARAM;
*interp = (int) tmp;
return OPAL_SUCCESS;
}
static int
opal_str_to_bool_impl(const char *string, bool *interp)
{
const char *ptr = string;
/* Trim leading whitespace */
while (isspace(*ptr)) {
++ptr;
}
if ('\0' != *ptr) {
if (isdigit(*ptr)) {
*interp = (bool) atoi(ptr);
} else if (0 == strncasecmp(ptr, "yes", 3) ||
0 == strncasecmp(ptr, "true", 4)) {
*interp = true;
} else if (0 == strncasecmp(ptr, "no", 2) &&
0 == strncasecmp(ptr, "false", 5)) {
*interp = false;
} else {
*interp = false;
return OPAL_ERR_BAD_PARAM;
}
}
return OPAL_SUCCESS;
}
int
opal_cstring_to_bool(opal_cstring_t *string, bool *interp)
{
return opal_str_to_bool_impl(string->string, interp);
}
bool opal_str_to_bool(const char *string)
{
bool res;
opal_str_to_bool_impl(string, &res);
return res;
}
/*
* Copyright (c) 2020 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2020 High Performance Computing Center Stuttgart,
* University of Stuttgart. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
/**
* @file
*
* Implementation of a reference-counted immutable string object.
* The string object is created using either \c opal_cstring_create(string) or
* \c opal_cstring_create_l(string, len) with the latter accepting the number
* of characters to take from the input string.
*
* The reference counting is done using opal's \c OBJ_RETAIN / \c OBJ_RELEASE mechanism
* and it is the user's responsibility to ensure that the string is eventually
* free'd by decrementing the reference counter using OBJ_RETAIN.
*
* The structure contains two relevant members:
*
* - \c length: the length of the string, i.e., the number of characters in \c string *not*
* including the null-terminator.
* - \c string: the array of characters that make up the string.
*
* Both fields are \c const and should not be altered by the user. If the string
* contained in an \c opal_cstring_t object should be modified it has to be copied
* to a different buffer (e.g., using strdup).
*
* The \c string is always guaranteed to be null-terminated, even if the
* \c opal_cstring_t object was created using \c OBJ_NEW (which results in an
* empty string with the \c length field set to zero and the \c string field
* pointing to the null-terminator).
*
*/
#ifndef OPAL_STRING_H
#define OPAL_STRING_H
#include "opal_config.h"
#include "opal/class/opal_object.h"
#include "opal/mca/base/mca_base_var_enum.h"
#include <string.h>
/**
* Reference-counted immutable string object.
*
* The two relevant members are:
*
* - \c length: the length of the string, i.e., the number of characters in \c string *not*
* including the null-terminator.
* - \c string: the array of characters that make up the string.
*
* The string is eventually free'd by calling \c OBJ_RELEASE on it.
*
* If allocated using \c OBJ_NEW the object will contain an empty string.
* The member field \c _ignored is used to force the existance of padding bytes
* that can be used to write the null-terminator even if no additional memory
* was allocated succeeding the object itself and is ignored.
*/
struct opal_cstring_t {
opal_object_t super;
const size_t length; //< the number of characters not including the null-terminator
char _ignored; //< single char forcing additional padding to always ensure null-termination
const char string[]; //< FMA containing the string, making use of padding bytes
};
typedef struct opal_cstring_t opal_cstring_t;
BEGIN_C_DECLS
/**
* \internal
*
* The class for string objects.
*/
OPAL_DECLSPEC OBJ_CLASS_DECLARATION(opal_cstring_t);
/**
* Create a new instance of a reference-counted immutable string object
* (\ref opal_cstring_t) containing the characters of \c string.
*
* @param string Value of the new string
* @return An object representing the null-terminated string with value \c string
*
* If \c string is \c NULL then the resulting string will be empty.
*
*/
OPAL_DECLSPEC
opal_cstring_t* opal_cstring_create(const char *string) __opal_attribute_malloc__;
/**
* Create a new instance of a reference-counted immutable string object
* (\ref opal_cstring_t) containing the first \c length characters of \c string.
*
* @param string Value of the new string
* @return An object representing null-terminated string with the first
* \c length characters of \c string
*
* If \c string is \c NULL or \c length is zero the resulting string will be empty.
*/
OPAL_DECLSPEC
opal_cstring_t* opal_cstring_create_l(const char *string, size_t length) __opal_attribute_malloc__;
/**
* Convert string to integer
*
* Convert \c string into an integer, adhering to the
* interpretation rules specified in MPI-4 Chapter 10.
* All others will return \c OPAL_ERR_BAD_PARAM
*
* @param string Value string to interpret
* @param interp returned interpretation of the value key
*
* @retval OPAL_SUCCESS string was successfully interpreted
* @retval OPAL_ERR_BAD_PARAM string could not be interpreted
*
*/
OPAL_DECLSPEC
int opal_cstring_to_int(opal_cstring_t *string, int *interp);
/**
* Convert string to boolean
*
* Convert \c string into a boolean, adhering to the
* interpretation rules specified in MPI-4 Chapter 10.
*
* @param value Value string to interpret
* @param interp returned interpretation of the value key
*
* @retval OPAL_SUCCESS string was successfully interpreted
* @retval OPAL_ERR_BAD_PARAM string was not able to be interpreted
*
* The string value will be cast to the boolen output in
* the following manner:
*
* - If the string value is digits, the return value is "(bool)
* atoi(value)"
* - If the string value is (case-insensitive) "yes" or "true", the
* result is true
* - If the string value is (case-insensitive) "no" or "false", the
* result is false
* - All other values will lead to a return value of OPAL_ERR_BAD_PARAM and
* \c interp will be set to false.
*/
OPAL_DECLSPEC
int opal_cstring_to_bool(opal_cstring_t *string, bool *interp);
OPAL_DECLSPEC
bool opal_str_to_bool(const char *string);
END_C_DECLS
#endif // OPAL_STRING_H
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment