Remove constraint of calling string_end_p
before string_next or string_get_cref This generates slighty more code but it is much saner from user point of view.
This commit is contained in:
1 parent
87f1e53e13
commit
3aa3e95e4c
3 files changed
+28
-48
No files matched your search
@@ -5341,8 +5341,6 @@ false otherwise.
|
||||
##### void string\_next (string\_it\_t it)
|
||||
|
||||
Move the iterator to the next UTF8 encoded code point.
|
||||
string\_end\_p shall have been called at least once
|
||||
per UTF8 code point before.
|
||||
|
||||
##### void string\_previous (string\_it\_t it)
|
||||
|
||||
@@ -5351,8 +5349,6 @@ Move the iterator to the previous UTF8 encoded code point.
|
||||
##### string\_unicode\_t string\_get\_cref (const string\_it\_t it)
|
||||
|
||||
Return the unicode code point associated to the iterator.
|
||||
string\_end\_p shall have been called at least once
|
||||
per UTF8 code point before.
|
||||
It returns -1 in case of error in decoding the UTF8 string.
|
||||
|
||||
##### size\_t string\_it\_get\_pos (const string\_it\_t it)
|
||||
|
||||
+28
-39
@@ -74,7 +74,6 @@ typedef enum {
|
||||
#define M_STR1NG_IT_CONTRACT(it) do { \
|
||||
M_ASSERT( (it) != NULL); \
|
||||
M_ASSERT( (it)->ptr != NULL); \
|
||||
M_ASSERT( 0 <= (it)->next_ptr && (it)->next_ptr <= M_STR1NG_MAX_BYTE_UTF8); \
|
||||
M_ASSERT( (it)->string != NULL); \
|
||||
M_ASSERT( m_string_get_cstr((it)->string) <= (it)->ptr); \
|
||||
M_ASSERT( (it)->ptr <= &m_string_get_cstr((it)->string)[m_string_size((it)->string)]); \
|
||||
@@ -129,7 +128,6 @@ typedef uint32_t m_string_unicode_t;
|
||||
/* Iterator on a string over UTF8 encoded code points */
|
||||
typedef struct m_string_it_s {
|
||||
m_string_unicode_t u; // Decoded Unicode code point for the iterator
|
||||
int next_ptr; // Offset to the next code point
|
||||
const char *ptr;
|
||||
m_string_srcptr string;
|
||||
} m_string_it_t[1];
|
||||
@@ -1716,7 +1714,6 @@ m_string_it(m_string_it_t it, const m_string_t str)
|
||||
M_STR1NG_CONTRACT(str);
|
||||
M_ASSERT(it != NULL);
|
||||
it->ptr = m_string_get_cstr(str);
|
||||
it->next_ptr = 0;
|
||||
it->u = 0;
|
||||
it->string = str;
|
||||
M_STR1NG_IT_CONTRACT(it);
|
||||
@@ -1731,7 +1728,6 @@ m_string_it_end(m_string_it_t it, const m_string_t str)
|
||||
M_STR1NG_CONTRACT(str);
|
||||
M_ASSERT(it != NULL);
|
||||
it->ptr = &m_string_get_cstr(str)[m_string_size(str)];
|
||||
it->next_ptr = 0;
|
||||
it->u = 0;
|
||||
it->string = str;
|
||||
M_STR1NG_IT_CONTRACT(it);
|
||||
@@ -1742,8 +1738,8 @@ static inline void
|
||||
m_string_it_set(m_string_it_t it, const m_string_it_t itsrc)
|
||||
{
|
||||
M_ASSERT(it != NULL && itsrc != NULL);
|
||||
M_STR1NG_IT_CONTRACT(itsrc);
|
||||
it->ptr = itsrc->ptr;
|
||||
it->next_ptr = itsrc->next_ptr;
|
||||
it->u = itsrc->u;
|
||||
it->string = itsrc->string;
|
||||
M_STR1NG_IT_CONTRACT(it);
|
||||
@@ -1762,7 +1758,6 @@ m_string_it_pos(m_string_it_t it, const m_string_t str, const size_t n)
|
||||
// The offset shall reference the first Byte of an UTF 8 Code point
|
||||
M_ASSERT(m_str1ng_utf8_start_p ((unsigned char)m_string_get_cstr(str)[n]));
|
||||
it->ptr = &m_string_get_cstr(str)[n];
|
||||
it->next_ptr = 0;
|
||||
it->u = 0;
|
||||
it->string = str;
|
||||
M_STR1NG_IT_CONTRACT(it);
|
||||
@@ -1778,32 +1773,12 @@ m_string_it_get_pos(m_string_it_t it)
|
||||
return (size_t) (it->ptr - m_string_get_cstr(it->string));
|
||||
}
|
||||
|
||||
/* Test if the iterator has reached the end of the string.
|
||||
As it is where we perform the UTF8 decoding, the user
|
||||
needs to call this function at least once before any other
|
||||
function, which is normally the case as the user shall test
|
||||
if the stream is not empty before reading it. */
|
||||
/* Test if the iterator has reached the end of the string. */
|
||||
static inline bool
|
||||
m_string_end_p (m_string_it_t it)
|
||||
{
|
||||
M_STR1NG_IT_CONTRACT(it);
|
||||
if (M_UNLIKELY (*it->ptr == 0)) {
|
||||
it->next_ptr = 0; // For safety, don't advance iterator over end of string
|
||||
return true;
|
||||
}
|
||||
m_str1ng_utf8_state_e state = M_STR1NG_UTF8_STARTING;
|
||||
m_string_unicode_t u = 0;
|
||||
const char *str = it->ptr;
|
||||
do {
|
||||
m_str1ng_utf8_decode(*str, &state, &u);
|
||||
str++;
|
||||
} while (state != M_STR1NG_UTF8_STARTING && state != M_STR1NG_UTF8_ERROR && *str != 0);
|
||||
// Save where the current unicode value ends in the UTF8 steam
|
||||
M_ASSERT( (str > it->ptr) && (str - it->ptr) <= M_STR1NG_MAX_BYTE_UTF8);
|
||||
it->next_ptr = (int) (str - it->ptr);
|
||||
// Save the decoded unicode value
|
||||
it->u = M_UNLIKELY (state == M_STR1NG_UTF8_ERROR) ? M_STRING_UNICODE_ERROR : u;
|
||||
return false;
|
||||
return it->ptr[0] == 0;
|
||||
}
|
||||
|
||||
/* Test if the iterator is equal to the other one */
|
||||
@@ -1812,8 +1787,6 @@ m_string_it_equal_p(const m_string_it_t it1, const m_string_it_t it2)
|
||||
{
|
||||
M_STR1NG_IT_CONTRACT(it1);
|
||||
M_STR1NG_IT_CONTRACT(it2);
|
||||
// IT1.ptr == IT2.ptr ==> IT1 == IT2 ==> All fields are equal
|
||||
M_ASSERT(it1->ptr != it2->ptr || (it1->next_ptr == it2->next_ptr && it1->u == it2->u));
|
||||
return it1->ptr == it2->ptr;
|
||||
}
|
||||
|
||||
@@ -1822,8 +1795,16 @@ static inline void
|
||||
m_string_next (m_string_it_t it)
|
||||
{
|
||||
M_STR1NG_IT_CONTRACT(it);
|
||||
// We already decoded the UTF8 stream
|
||||
it->ptr += it->next_ptr;
|
||||
const char *ptr = it->ptr;
|
||||
while (*ptr != 0) {
|
||||
ptr ++;
|
||||
if (m_str1ng_utf8_start_p((unsigned char) *ptr) ) {
|
||||
/* Start of an UTF 8 code point */
|
||||
break;
|
||||
}
|
||||
}
|
||||
it->ptr = ptr;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Move the iterator to the previous code point */
|
||||
@@ -1838,16 +1819,11 @@ m_string_previous(m_string_it_t it)
|
||||
if (m_str1ng_utf8_start_p((unsigned char) *ptr) ) {
|
||||
/* Start of an UTF 8 code point */
|
||||
it->ptr = ptr;
|
||||
/* Decode the UTF-8 code point */
|
||||
bool b = m_string_end_p(it);
|
||||
M_ASSERT(!b);
|
||||
(void) b;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* We reach the start of the string: mark the iterator to the end */
|
||||
it->ptr = &org[m_string_size(it->string)];
|
||||
it->next_ptr = 0;
|
||||
M_STR1NG_IT_CONTRACT(it);
|
||||
}
|
||||
|
||||
@@ -1856,14 +1832,27 @@ static inline m_string_unicode_t
|
||||
m_string_get_cref (const m_string_it_t it)
|
||||
{
|
||||
M_STR1NG_IT_CONTRACT(it);
|
||||
return it->u;
|
||||
M_ASSERT(*it->ptr != 0);
|
||||
|
||||
m_str1ng_utf8_state_e state = M_STR1NG_UTF8_STARTING;
|
||||
m_string_unicode_t u = 0;
|
||||
const char *str = it->ptr;
|
||||
do {
|
||||
m_str1ng_utf8_decode(*str, &state, &u);
|
||||
str++;
|
||||
} while (state != M_STR1NG_UTF8_STARTING && state != M_STR1NG_UTF8_ERROR && *str != 0);
|
||||
// Save where the current unicode value ends in the UTF8 steam
|
||||
M_ASSERT( (str > it->ptr) && (str - it->ptr) <= M_STR1NG_MAX_BYTE_UTF8);
|
||||
// Save the decoded unicode value
|
||||
return M_UNLIKELY (state == M_STR1NG_UTF8_ERROR) ? M_STRING_UNICODE_ERROR : u;
|
||||
}
|
||||
|
||||
/* Return the unicode code point associated to the iterator */
|
||||
static inline const m_string_unicode_t *
|
||||
m_string_cref (const m_string_it_t it)
|
||||
m_string_cref (m_string_it_t it)
|
||||
{
|
||||
M_STR1NG_IT_CONTRACT(it);
|
||||
it->u = m_string_get_cref(it);
|
||||
return &it->u;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,15 +41,10 @@ static void test_utf8_basic(void)
|
||||
char *buf = m_str1ng_get_cstr(s);
|
||||
/* Low level access for internal testing */
|
||||
it->ptr = buf;
|
||||
it->next_ptr = 0;
|
||||
it->string = s;
|
||||
m_str1ng_utf8_encode (buf, i);
|
||||
m_str1ng_set_size(s, strlen(buf));
|
||||
bool b = string_end_p(it);
|
||||
assert (b == false);
|
||||
assert (it->u == i);
|
||||
assert (string_get_cref(it) == i);
|
||||
assert (it->ptr[it->next_ptr] == 0);
|
||||
assert (m_str1ng_utf8_length(buf) == 1);
|
||||
assert (m_str1ng_utf8_valid_str_p(buf) == true);
|
||||
/* Higher level access */
|
||||
|
||||
Reference in new issue
Block a user