Update after internal review.

This commit is contained in:
Patrick Pelissier committed 2018-07-16 21:43:17 +02:00
1 parent 001272820c
commit 4af48724ce
1 file changed
+29 -13
+29 -13
View File
@@ -40,6 +40,9 @@
# define STRINGI_ASSUME(n) (void) 0 # define STRINGI_ASSUME(n) (void) 0
#endif #endif
/* Minimum allocated string is at least 16 chars */
#define STRINGI_MIN_ALLOC_SIZE 16
// 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.
@@ -60,9 +63,11 @@
/* */ /* */
/***********************************************************************/ /***********************************************************************/
/* Index returned in case of error */ /* Index returned in case of error instead of the position within the string */
#define STRING_FAILURE ((size_t)-1) #define STRING_FAILURE ((size_t)-1)
/* This is the main structure of this module.
It is not designed to be memory efficient. */
typedef struct string_s { typedef struct string_s {
size_t size, alloc; size_t size, alloc;
char *ptr; char *ptr;
@@ -76,8 +81,9 @@ typedef enum string_fgets_s {
static inline void static inline void
string_init(string_t v) string_init(string_t v)
{ {
v->size = v->alloc = 0; v->size = 0;
v->ptr = NULL; v->alloc = 0;
v->ptr = NULL;
STRINGI_CONTRACT(v); STRINGI_CONTRACT(v);
} }
@@ -86,20 +92,23 @@ string_clear(string_t v)
{ {
STRINGI_CONTRACT(v); STRINGI_CONTRACT(v);
M_MEMORY_FREE(v->ptr); M_MEMORY_FREE(v->ptr);
v->size = v->alloc = 0; /* This is not needed but is safer. size is not set to make
v->ptr = NULL; the string more or less invalid so that it can be detected. */
v->alloc = 0;
v->ptr = NULL;
} }
/* NOTE: Internaly used by STRING_DECL_INIT */ /* NOTE: Internaly used by STRING_DECL_INIT */
static inline void stringi_clear2(string_t *v) { string_clear(*v); } static inline void stringi_clear2(string_t *v) { string_clear(*v); }
/* NOTE: Returned pointer has to be released by M_MEMORY_FREE. */ /* NOTE: The ownership of the data is transfered back to the caller
and the returned pointer has to be released by M_MEMORY_FREE. */
static inline char * static inline char *
string_clear_get_str(string_t v) string_clear_get_str(string_t v)
{ {
STRINGI_CONTRACT(v); STRINGI_CONTRACT(v);
char *p = v->ptr; char *p = v->ptr;
v->size = v->alloc = 0; v->alloc = 0;
v->ptr = NULL; v->ptr = NULL;
return p; return p;
} }
@@ -150,16 +159,19 @@ stringi_fit2size (string_t v, size_t size)
// Note: this function may be called in context where the contract // Note: this function may be called in context where the contract
// is not fullfilled. // is not fullfilled.
if (size > v->alloc) { if (size > v->alloc) {
size_t alloc = size < 16 ? 16 : (size + size / 2); size_t alloc = size < STRINGI_MIN_ALLOC_SIZE ? STRINGI_MIN_ALLOC_SIZE : (size + size / 2);
if (M_UNLIKELY (alloc <= v->alloc)) { if (M_UNLIKELY (alloc <= v->alloc)) {
/* Overflow in alloc computation */
M_MEMORY_FULL(sizeof (char) * alloc); M_MEMORY_FULL(sizeof (char) * alloc);
// NOTE: Return is broken... // NOTE: Return is broken...
abort();
return; return;
} }
char *ptr = M_MEMORY_REALLOC (char, v->ptr, alloc); char *ptr = M_MEMORY_REALLOC (char, v->ptr, alloc);
if (M_UNLIKELY (ptr == NULL)) { if (M_UNLIKELY (ptr == NULL)) {
M_MEMORY_FULL(sizeof (char) * alloc); M_MEMORY_FULL(sizeof (char) * alloc);
// NOTE: Return is broken... // NOTE: Return is broken...
abort();
return; return;
} }
v->ptr = ptr; v->ptr = ptr;
@@ -179,8 +191,9 @@ string_reserve(string_t v, size_t alloc)
if (M_UNLIKELY (alloc == 1)) { if (M_UNLIKELY (alloc == 1)) {
// Only 1 byte reserved for the NUL char ==> free // Only 1 byte reserved for the NUL char ==> free
M_MEMORY_FREE(v->ptr); M_MEMORY_FREE(v->ptr);
v->size = v->alloc = 0; v->size = 0;
v->ptr = NULL; v->alloc = 0;
v->ptr = NULL;
} else { } else {
char *ptr = M_MEMORY_REALLOC (char, v->ptr, alloc); char *ptr = M_MEMORY_REALLOC (char, v->ptr, alloc);
if (M_UNLIKELY (ptr == NULL) ) { if (M_UNLIKELY (ptr == NULL) ) {
@@ -251,7 +264,6 @@ string_set_n(string_t v, const string_t ref, size_t offset, size_t length)
STRINGI_CONTRACT (v); STRINGI_CONTRACT (v);
STRINGI_CONTRACT (ref); STRINGI_CONTRACT (ref);
assert (offset <= ref->size); assert (offset <= ref->size);
assert (v != ref); // Not supported yet
if (M_UNLIKELY (ref->size == 0)) { if (M_UNLIKELY (ref->size == 0)) {
v->size = 0; v->size = 0;
if (v->ptr) { if (v->ptr) {
@@ -259,8 +271,13 @@ string_set_n(string_t v, const string_t ref, size_t offset, size_t length)
} }
} else { } else {
assert (ref->ptr != NULL); assert (ref->ptr != NULL);
string_set_strn(v, ref->ptr + offset, length); size_t size = M_MIN (ref->size - offset, length);
stringi_fit2size(v, size+1);
memmove(v->ptr, ref->ptr + offset, size);
v->ptr[size] = 0;
v->size = size;
} }
STRINGI_CONTRACT (v);
} }
static inline void static inline void
@@ -285,7 +302,6 @@ string_init_move(string_t v1, string_t v2)
v1->alloc = v2->alloc; v1->alloc = v2->alloc;
v1->ptr = v2->ptr; v1->ptr = v2->ptr;
// Note: nullify v2 to be safer // Note: nullify v2 to be safer
v2->size = 0;
v2->alloc = 0; v2->alloc = 0;
v2->ptr = NULL; v2->ptr = NULL;
STRINGI_CONTRACT (v1); STRINGI_CONTRACT (v1);