Skip to content

Commit aa25d10

Browse files
committed
Add opal_cstring_t, a reference-counted constant string object
Signed-off-by: Joseph Schuchart <[email protected]>
1 parent 96fce24 commit aa25d10

File tree

3 files changed

+310
-0
lines changed

3 files changed

+310
-0
lines changed

opal/class/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
# Source code files
2828
headers += \
2929
class/opal_bitmap.h \
30+
class/opal_cstring.h \
3031
class/opal_free_list.h \
3132
class/opal_hash_table.h \
3233
class/opal_hotel.h \
@@ -43,6 +44,7 @@ headers += \
4344

4445
lib@OPAL_LIB_PREFIX@open_pal_la_SOURCES += \
4546
class/opal_bitmap.c \
47+
class/opal_cstring.c \
4648
class/opal_free_list.c \
4749
class/opal_hash_table.c \
4850
class/opal_hotel.c \

opal/class/opal_cstring.c

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
* Copyright (c) 2020 The University of Tennessee and The University
3+
* of Tennessee Research Foundation. All rights
4+
* reserved.
5+
* Copyright (c) 2020 High Performance Computing Center Stuttgart,
6+
* University of Stuttgart. All rights reserved.
7+
* $COPYRIGHT$
8+
*
9+
* Additional copyrights may follow
10+
*
11+
* $HEADER$
12+
*/
13+
14+
#include "opal_cstring.h"
15+
16+
#include <errno.h>
17+
#include <ctype.h>
18+
#include <stddef.h>
19+
#include "opal/constants.h"
20+
#include "opal/util/string_copy.h"
21+
22+
static void opal_cstring_ctor(opal_cstring_t *obj);
23+
24+
OBJ_CLASS_INSTANCE(
25+
opal_cstring_t,
26+
opal_object_t,
27+
&opal_cstring_ctor,
28+
NULL
29+
);
30+
31+
/* make sure we have sufficient padding to always null-terminate the string */
32+
#if (__STDC_VERSION__ >= 201112L)
33+
_Static_assert(sizeof(opal_cstring_t) > offsetof(opal_cstring_t, string),
34+
"Insufficient padding available in opal_cstring_t");
35+
#endif // (__STDC_VERSION__ >= 201112L)
36+
37+
static void opal_cstring_ctor(opal_cstring_t *obj)
38+
{
39+
*(size_t*)&(obj->length) = 0;
40+
/* make sure the string is null-terminated */
41+
((char*)obj->string)[0] = '\n';
42+
}
43+
44+
static inline size_t opal_cstring_alloc_size(size_t len)
45+
{
46+
/* the size required for the object and the string, incl. the null-terminator */
47+
size_t res = sizeof(opal_cstring_t) + len + 1;
48+
/* adjust for the additional padding that is used for the string anyway */
49+
res -= (sizeof(opal_cstring_t) - offsetof(opal_cstring_t, string));
50+
/* make sure we allocate at least sizeof(opal_cstring_t) */
51+
return (res > sizeof(opal_cstring_t)) ? res : sizeof(opal_cstring_t);
52+
}
53+
54+
opal_cstring_t* opal_cstring_create_l(const char *string, size_t len)
55+
{
56+
if (NULL == string || 0 == len) {
57+
return OBJ_NEW(opal_cstring_t);
58+
}
59+
60+
/* Allocate space for the object, the characters in \c string and the terminating null */
61+
opal_cstring_t* res = (opal_cstring_t*)malloc(opal_cstring_alloc_size(len));
62+
if (NULL == res) {
63+
return NULL;
64+
}
65+
OBJ_CONSTRUCT(res, opal_cstring_t);
66+
67+
/* cast away const for setting the member values */
68+
*(size_t*)&(res->length) = len;
69+
opal_string_copy((char*)res->string, string, len+1);
70+
71+
return res;
72+
}
73+
74+
opal_cstring_t* opal_cstring_create(const char *string)
75+
{
76+
if (NULL == string) {
77+
return OBJ_NEW(opal_cstring_t);
78+
}
79+
size_t len = strlen(string);
80+
return opal_cstring_create_l(string, len);
81+
}
82+
83+
84+
int opal_cstring_to_int(opal_cstring_t *string, int *interp)
85+
{
86+
long tmp;
87+
char *endp;
88+
89+
if (NULL == string || '\0' == string->string[0]) {
90+
return OPAL_ERR_BAD_PARAM;
91+
}
92+
93+
errno = 0;
94+
tmp = strtol(string->string, &endp, 10);
95+
/* we found something not a number */
96+
if (*endp != '\0') return OPAL_ERR_BAD_PARAM;
97+
/* underflow */
98+
if (tmp == 0 && errno == EINVAL) return OPAL_ERR_BAD_PARAM;
99+
100+
*interp = (int) tmp;
101+
102+
return OPAL_SUCCESS;
103+
}
104+
105+
106+
static int
107+
opal_str_to_bool_impl(const char *string, bool *interp)
108+
{
109+
const char *ptr = string;
110+
111+
/* Trim leading whitespace */
112+
while (isspace(*ptr)) {
113+
++ptr;
114+
}
115+
116+
if ('\0' != *ptr) {
117+
if (isdigit(*ptr)) {
118+
*interp = (bool) atoi(ptr);
119+
} else if (0 == strncasecmp(ptr, "yes", 3) ||
120+
0 == strncasecmp(ptr, "true", 4)) {
121+
*interp = true;
122+
} else if (0 == strncasecmp(ptr, "no", 2) &&
123+
0 == strncasecmp(ptr, "false", 5)) {
124+
*interp = false;
125+
} else {
126+
*interp = false;
127+
return OPAL_ERR_BAD_PARAM;
128+
}
129+
}
130+
return OPAL_SUCCESS;
131+
}
132+
133+
int
134+
opal_cstring_to_bool(opal_cstring_t *string, bool *interp)
135+
{
136+
return opal_str_to_bool_impl(string->string, interp);
137+
}
138+
139+
bool opal_str_to_bool(const char *string)
140+
{
141+
bool res;
142+
opal_str_to_bool_impl(string, &res);
143+
return res;
144+
}

opal/class/opal_cstring.h

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* Copyright (c) 2020 The University of Tennessee and The University
3+
* of Tennessee Research Foundation. All rights
4+
* reserved.
5+
* Copyright (c) 2020 High Performance Computing Center Stuttgart,
6+
* University of Stuttgart. All rights reserved.
7+
* $COPYRIGHT$
8+
*
9+
* Additional copyrights may follow
10+
*
11+
* $HEADER$
12+
*/
13+
14+
/**
15+
* @file
16+
*
17+
* Implementation of a reference-counted immutable string object.
18+
* The string object is created using either \c opal_cstring_create(string) or
19+
* \c opal_cstring_create_l(string, len) with the latter accepting the number
20+
* of characters to take from the input string.
21+
*
22+
* The reference counting is done using opal's \c OBJ_RETAIN / \c OBJ_RELEASE mechanism
23+
* and it is the user's responsibility to ensure that the string is eventually
24+
* free'd by decrementing the reference counter using OBJ_RETAIN.
25+
*
26+
* The structure contains two relevant members:
27+
*
28+
* - \c length: the length of the string, i.e., the number of characters in \c string *not*
29+
* including the null-terminator.
30+
* - \c string: the array of characters that make up the string.
31+
*
32+
* Both fields are \c const and should not be altered by the user. If the string
33+
* contained in an \c opal_cstring_t object should be modified it has to be copied
34+
* to a different buffer (e.g., using strdup).
35+
*
36+
* The \c string is always guaranteed to be null-terminated, even if the
37+
* \c opal_cstring_t object was created using \c OBJ_NEW (which results in an
38+
* empty string with the \c length field set to zero and the \c string field
39+
* pointing to the null-terminator).
40+
*
41+
*/
42+
43+
#ifndef OPAL_STRING_H
44+
#define OPAL_STRING_H
45+
46+
#include "opal_config.h"
47+
#include "opal/class/opal_object.h"
48+
#include "opal/mca/base/mca_base_var_enum.h"
49+
50+
#include <string.h>
51+
52+
/**
53+
* Reference-counted immutable string object.
54+
*
55+
* The two relevant members are:
56+
*
57+
* - \c length: the length of the string, i.e., the number of characters in \c string *not*
58+
* including the null-terminator.
59+
* - \c string: the array of characters that make up the string.
60+
*
61+
* The string is eventually free'd by calling \c OBJ_RELEASE on it.
62+
*
63+
* If allocated using \c OBJ_NEW the object will contain an empty string.
64+
* The member field \c _ignored is used to force the existance of padding bytes
65+
* that can be used to write the null-terminator even if no additional memory
66+
* was allocated succeeding the object itself and is ignored.
67+
*/
68+
struct opal_cstring_t {
69+
opal_object_t super;
70+
const size_t length; //< the number of characters not including the null-terminator
71+
char _ignored; //< single char forcing additional padding to always ensure null-termination
72+
const char string[]; //< FMA containing the string, making use of padding bytes
73+
};
74+
75+
typedef struct opal_cstring_t opal_cstring_t;
76+
77+
78+
BEGIN_C_DECLS
79+
80+
/**
81+
* \internal
82+
*
83+
* The class for string objects.
84+
*/
85+
OPAL_DECLSPEC OBJ_CLASS_DECLARATION(opal_cstring_t);
86+
87+
/**
88+
* Create a new instance of a reference-counted immutable string object
89+
* (\ref opal_cstring_t) containing the characters of \c string.
90+
*
91+
* @param string Value of the new string
92+
* @return An object representing the null-terminated string with value \c string
93+
*
94+
* If \c string is \c NULL then the resulting string will be empty.
95+
*
96+
*/
97+
OPAL_DECLSPEC
98+
opal_cstring_t* opal_cstring_create(const char *string) __opal_attribute_malloc__;
99+
100+
/**
101+
* Create a new instance of a reference-counted immutable string object
102+
* (\ref opal_cstring_t) containing the first \c length characters of \c string.
103+
*
104+
* @param string Value of the new string
105+
* @return An object representing null-terminated string with the first
106+
* \c length characters of \c string
107+
*
108+
* If \c string is \c NULL or \c length is zero the resulting string will be empty.
109+
*/
110+
OPAL_DECLSPEC
111+
opal_cstring_t* opal_cstring_create_l(const char *string, size_t length) __opal_attribute_malloc__;
112+
113+
/**
114+
* Convert string to integer
115+
*
116+
* Convert \c string into an integer, adhering to the
117+
* interpretation rules specified in MPI-4 Chapter 10.
118+
* All others will return \c OPAL_ERR_BAD_PARAM
119+
*
120+
* @param string Value string to interpret
121+
* @param interp returned interpretation of the value key
122+
*
123+
* @retval OPAL_SUCCESS string was successfully interpreted
124+
* @retval OPAL_ERR_BAD_PARAM string could not be interpreted
125+
*
126+
*/
127+
OPAL_DECLSPEC
128+
int opal_cstring_to_int(opal_cstring_t *string, int *interp);
129+
130+
131+
/**
132+
* Convert string to boolean
133+
*
134+
* Convert \c string into a boolean, adhering to the
135+
* interpretation rules specified in MPI-4 Chapter 10.
136+
*
137+
* @param value Value string to interpret
138+
* @param interp returned interpretation of the value key
139+
*
140+
* @retval OPAL_SUCCESS string was successfully interpreted
141+
* @retval OPAL_ERR_BAD_PARAM string was not able to be interpreted
142+
*
143+
* The string value will be cast to the boolen output in
144+
* the following manner:
145+
*
146+
* - If the string value is digits, the return value is "(bool)
147+
* atoi(value)"
148+
* - If the string value is (case-insensitive) "yes" or "true", the
149+
* result is true
150+
* - If the string value is (case-insensitive) "no" or "false", the
151+
* result is false
152+
* - All other values will lead to a return value of OPAL_ERR_BAD_PARAM and
153+
* \c interp will be set to false.
154+
*/
155+
OPAL_DECLSPEC
156+
int opal_cstring_to_bool(opal_cstring_t *string, bool *interp);
157+
158+
159+
OPAL_DECLSPEC
160+
bool opal_str_to_bool(const char *string);
161+
162+
END_C_DECLS
163+
164+
#endif // OPAL_STRING_H

0 commit comments

Comments
 (0)