Add bounded string definition so that you can easily use them for a container.
This commit is contained in:
1 parent
479ad2d4ba
commit
8e114d6fe4
1 file changed
+237
-2
+237
-2
@@ -43,7 +43,7 @@
|
|||||||
// This macro defines the contract of a string.
|
// This macro defines the contract of a string.
|
||||||
// Note: A ==> B is represented as not(A) or B
|
// Note: A ==> B is represented as not(A) or B
|
||||||
// Note: use of strlen can slow down a lot the program in some cases.
|
// Note: use of strlen can slow down a lot the program in some cases.
|
||||||
#define STRINGI_CONTRACT(v) do { \
|
#define STRINGI_CONTRACT(v) do { \
|
||||||
M_ASSUME (v != NULL); \
|
M_ASSUME (v != NULL); \
|
||||||
M_ASSUME (v->ptr != NULL || (v->size == 0 && v->alloc == 0)); \
|
M_ASSUME (v->ptr != NULL || (v->size == 0 && v->alloc == 0)); \
|
||||||
STRINGI_ASSUME (v->ptr == NULL || v->size == strlen(v->ptr)); \
|
STRINGI_ASSUME (v->ptr == NULL || v->size == strlen(v->ptr)); \
|
||||||
@@ -52,7 +52,13 @@
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
/********************************** EXTERNAL ************************************/
|
/****************************** EXTERNAL *******************************/
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
/* */
|
||||||
|
/* DYNAMIC STRING */
|
||||||
|
/* */
|
||||||
|
/***********************************************************************/
|
||||||
|
|
||||||
/* Index returned in case of error */
|
/* Index returned in case of error */
|
||||||
#define STRING_FAILURE ((size_t)-1)
|
#define STRING_FAILURE ((size_t)-1)
|
||||||
@@ -137,6 +143,7 @@ string_empty_p(const string_t v)
|
|||||||
return v->size == 0;
|
return v->size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Size includes the final null char
|
||||||
static inline void
|
static inline void
|
||||||
stringi_fit2size (string_t v, size_t size)
|
stringi_fit2size (string_t v, size_t size)
|
||||||
{
|
{
|
||||||
@@ -1161,4 +1168,232 @@ namespace m_string {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
/* */
|
||||||
|
/* BOUNDED STRING, aka char[N+1] */
|
||||||
|
/* */
|
||||||
|
/***********************************************************************/
|
||||||
|
|
||||||
|
#define BOUNDED_STRING_DEF(name, size) \
|
||||||
|
\
|
||||||
|
typedef struct M_C(name, _s) { \
|
||||||
|
char s[size+1]; \
|
||||||
|
} M_C(name,_t)[1]; \
|
||||||
|
\
|
||||||
|
static inline void \
|
||||||
|
M_C(name, _init)(M_C(name,_t) s) \
|
||||||
|
{ \
|
||||||
|
assert(s != NULL); \
|
||||||
|
s->s[0] = 0; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void \
|
||||||
|
M_C(name, _clear)(M_C(name,_t) s) \
|
||||||
|
{ \
|
||||||
|
assert(s != NULL); \
|
||||||
|
/* nothing to do */ \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void \
|
||||||
|
M_C(name, _clean)(M_C(name,_t) s) \
|
||||||
|
{ \
|
||||||
|
assert(s != NULL); \
|
||||||
|
s->s[0] = 0; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline size_t \
|
||||||
|
M_C(name, _size)(const M_C(name,_t) s) \
|
||||||
|
{ \
|
||||||
|
assert(s != NULL); \
|
||||||
|
return strlen(s->s); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline size_t \
|
||||||
|
M_C(name, _capacity)(const M_C(name,_t) s) \
|
||||||
|
{ \
|
||||||
|
assert(s != NULL); \
|
||||||
|
(void)s; /* unused */ \
|
||||||
|
return size+1; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline char \
|
||||||
|
M_C(name, _get_char)(const M_C(name,_t) s, size_t index) \
|
||||||
|
{ \
|
||||||
|
assert(s != NULL); \
|
||||||
|
assert(index < size); \
|
||||||
|
return s->s[index]; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline bool \
|
||||||
|
M_C(name, _empty_p)(const M_C(name,_t) s) \
|
||||||
|
{ \
|
||||||
|
assert(s != NULL); \
|
||||||
|
return s->s[0] == 0; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void \
|
||||||
|
M_C(name, _set_str)(M_C(name,_t) s, const char str[]) \
|
||||||
|
{ \
|
||||||
|
assert (s != NULL && str != NULL); \
|
||||||
|
strncpy(s->s, str, size+1); \
|
||||||
|
s->s[size] = 0; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void \
|
||||||
|
M_C(name, _set_strn)(M_C(name,_t) s, const char str[], size_t n) \
|
||||||
|
{ \
|
||||||
|
assert (s != NULL && str != NULL); \
|
||||||
|
size_t len = M_MIN(size, n); \
|
||||||
|
strncpy(s->s, str, len+1); \
|
||||||
|
s->s[len] = 0; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline const char * \
|
||||||
|
M_C(name, _get_cstr)(const M_C(name,_t) s) \
|
||||||
|
{ \
|
||||||
|
assert (s != NULL); \
|
||||||
|
return s->s; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void \
|
||||||
|
M_C(name, _set)(M_C(name,_t) s, const M_C(name,_t) str) \
|
||||||
|
{ \
|
||||||
|
assert (s != NULL && str != NULL); \
|
||||||
|
M_C(name, _set_str)(s, str->s); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void \
|
||||||
|
M_C(name, _set_n)(M_C(name,_t) s, const M_C(name,_t) str, \
|
||||||
|
size_t offset, size_t length) \
|
||||||
|
{ \
|
||||||
|
assert (s != NULL && str != NULL); \
|
||||||
|
assert (offset <= size); \
|
||||||
|
M_C(name, _set_strn)(s, str->s+offset, length); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void \
|
||||||
|
M_C(name, _init_set)(M_C(name,_t) s, const M_C(name,_t) str) \
|
||||||
|
{ \
|
||||||
|
M_C(name,_init)(s); \
|
||||||
|
M_C(name,_set)(s, str); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void \
|
||||||
|
M_C(name, _init_set_str)(M_C(name,_t) s, const char str[]) \
|
||||||
|
{ \
|
||||||
|
M_C(name,_init)(s); \
|
||||||
|
M_C(name,_set_str)(s, str); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void \
|
||||||
|
M_C(name, _cat_str)(M_C(name,_t) s, const char str[]) \
|
||||||
|
{ \
|
||||||
|
assert (s != NULL && str != NULL); \
|
||||||
|
assert (strlen(s->s) <= size); \
|
||||||
|
strncat(s->s, str, size-strlen(s->s)); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void \
|
||||||
|
M_C(name, _cat)(M_C(name,_t) s, const M_C(name,_t) str) \
|
||||||
|
{ \
|
||||||
|
M_C(name, _cat_str)(s, str->s); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline int \
|
||||||
|
M_C(name, _cmp_str)(const M_C(name,_t) s, const char str[]) \
|
||||||
|
{ \
|
||||||
|
assert (s != NULL && str != NULL); \
|
||||||
|
return strcmp(s->s, str); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline int \
|
||||||
|
M_C(name, _cmp)(const M_C(name,_t) s, const M_C(name,_t) str) \
|
||||||
|
{ \
|
||||||
|
assert (s != NULL && str != NULL); \
|
||||||
|
return strcmp(s->s, str->s); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline int \
|
||||||
|
M_C(name, _equal_str_p)(const M_C(name,_t) s, const char str[]) \
|
||||||
|
{ \
|
||||||
|
assert (s != NULL && str != NULL); \
|
||||||
|
return strcmp(s->s, str) == 0; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline int \
|
||||||
|
M_C(name, _equal_p)(const M_C(name,_t) s, const M_C(name,_t) str) \
|
||||||
|
{ \
|
||||||
|
assert (s != NULL && str != NULL); \
|
||||||
|
return strcmp(s->s, str->s) == 0; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline int \
|
||||||
|
M_C(name, _printf)(M_C(name,_t) s, const char format[], ...) \
|
||||||
|
{ \
|
||||||
|
assert (s != NULL && format != NULL); \
|
||||||
|
va_list args; \
|
||||||
|
int ret; \
|
||||||
|
va_start (args, format); \
|
||||||
|
ret = vsnprintf (s->s, size+1, format, args); \
|
||||||
|
va_end (args); \
|
||||||
|
return ret; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline int \
|
||||||
|
M_C(name, _cat_printf)(M_C(name,_t) s, const char format[], ...) \
|
||||||
|
{ \
|
||||||
|
assert (s != NULL && format != NULL); \
|
||||||
|
va_list args; \
|
||||||
|
int ret; \
|
||||||
|
va_start (args, format); \
|
||||||
|
size_t length = strlen(s->s); \
|
||||||
|
assert(length <= size); \
|
||||||
|
ret = vsnprintf (&s->s[length], size+1-length, format, args); \
|
||||||
|
va_end (args); \
|
||||||
|
return ret; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline bool \
|
||||||
|
M_C(name, _fgets)(M_C(name,_t)s, FILE *f, string_fgets_t arg) \
|
||||||
|
{ \
|
||||||
|
assert (s != NULL && f != NULL); \
|
||||||
|
assert (arg != STRING_READ_FILE); \
|
||||||
|
char *ret = fgets(s->s, size+1, f); \
|
||||||
|
s->s[size] = 0; \
|
||||||
|
if (ret != NULL && arg == STRING_READ_PURE_LINE) { \
|
||||||
|
size_t length = strlen(s->s); \
|
||||||
|
if (length > 0 && s->s[length-1] == '\n') \
|
||||||
|
s->s[length-1] = 0; \
|
||||||
|
} \
|
||||||
|
return ret != NULL; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline bool \
|
||||||
|
M_C(name, _fputs)(FILE *f, const M_C(name,_t) s) \
|
||||||
|
{ \
|
||||||
|
assert(f != NULL && s != NULL); \
|
||||||
|
return fputs(s->s, f) >= 0; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline size_t \
|
||||||
|
M_C(name, _hash)(const M_C(name,_t) s) \
|
||||||
|
{ \
|
||||||
|
assert (s != NULL); \
|
||||||
|
/* Cannot use m_core_hash: not aligned on an int */ \
|
||||||
|
M_HASH_DECL(hash); \
|
||||||
|
const char *str = s->s; \
|
||||||
|
while (*str) M_HASH_UP(hash, *str++); \
|
||||||
|
return M_HASH_FINAL(hash); \
|
||||||
|
} \
|
||||||
|
|
||||||
|
|
||||||
|
/* Define the OPLIST of a BOUNDED_STRING */
|
||||||
|
#define BOUNDED_STRING_OPLIST(name) \
|
||||||
|
(INIT(M_C(name,_init)), INIT_SET(M_C(name,_init_set)), \
|
||||||
|
SET(M_C(name,_set)), CLEAR(M_C(name,_clear)), HASH(M_C(name,_hash)), \
|
||||||
|
EQUAL(M_C(name,_equal_p)), CMP(M_C(name,_cmp)), TYPE(M_C(name,_t)), \
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
Reference in new issue
Block a user