Skip to content

Commit f97883e

Browse files
String functions for trimming whitespace
1 parent 8f4ec31 commit f97883e

File tree

2 files changed

+84
-1
lines changed

2 files changed

+84
-1
lines changed

src/common/src/mlib/str.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,24 @@ _mstr_adjust_index(mstr_view s, mlib_upsized_integer pos, bool clamp_to_length)
288288
return pos.bits.as_unsigned;
289289
}
290290

291+
/**
292+
* @brief Obtain the code unit at the given zero-based index, with negative index wrapping.
293+
*
294+
* This function asserts that the index is in-bounds for the given string.
295+
*
296+
* @param s The string to be inspected.
297+
* @param pos The index to access. Zero is the first code unit, and -1 is the last.
298+
* @return char The code unit at position `pos`.
299+
*/
300+
static inline char
301+
mstr_at(mstr_view s, mlib_upsized_integer pos_)
302+
{
303+
size_t pos = _mstr_adjust_index(s, pos_, false);
304+
return s.data[pos];
305+
}
306+
307+
#define mstr_at(S, Pos) (mstr_at)(mstr_view_from(S), mlib_upsize_integer(Pos))
308+
291309
/**
292310
* @brief Create a new `mstr_view` that views a substring within another string
293311
*
@@ -441,6 +459,63 @@ mstr_find_first_of(mstr_view hay, mstr_view const needles, mlib_upsized_integer
441459
#define _mstr_find_first_of_argc_3(Hay, Needle, Pos) _mstr_find_first_of_argc_4(Hay, Needle, Pos, SIZE_MAX)
442460
#define _mstr_find_first_of_argc_4(Hay, Needle, Pos, Len) mstr_find_first_of(Hay, Needle, mlib_upsize_integer(Pos), Len)
443461

462+
/**
463+
* @brief Trim leading latin (ASCII) whitespace from the given string
464+
*
465+
* @param s The string to be inspected
466+
* @return mstr_view A substring view of `s` that excludes any leading whitespace
467+
*/
468+
static inline mstr_view
469+
mstr_trim_left(mstr_view s)
470+
{
471+
while (s.len) {
472+
char c = mstr_at(s, 0);
473+
if (c == ' ' || c == '\n' || c == '\r' || c == '\t') {
474+
s = mstr_substr(s, 1);
475+
} else {
476+
break;
477+
}
478+
}
479+
return s;
480+
}
481+
#define mstr_trim_left(S) (mstr_trim_left)(mstr_view_from(S))
482+
483+
/**
484+
* @brief Trim trailing latin (ASCII) whitespace from the given string
485+
*
486+
* @param s The string to be insepcted
487+
* @return mstr_view A substring view of `s` that excludes any trailing whitespace.
488+
*/
489+
static inline mstr_view
490+
mstr_trim_right(mstr_view s)
491+
{
492+
while (s.len) {
493+
char c = mstr_at(s, -1);
494+
if (c == ' ' || c == '\n' || c == '\r' || c == '\t') {
495+
s = mstr_slice(s, 0, -1);
496+
} else {
497+
break;
498+
}
499+
}
500+
return s;
501+
}
502+
#define mstr_trim_right(S) (mstr_trim_right)(mstr_view_from(S))
503+
504+
/**
505+
* @brief Trim leading and trailing latin (ASCII) whitespace from the string
506+
*
507+
* @param s The string to be inspected
508+
* @return mstr_view A substring of `s` that excludes leading and trailing whitespace.
509+
*/
510+
static inline mstr_view
511+
mstr_trim(mstr_view s)
512+
{
513+
s = mstr_trim_left(s);
514+
s = mstr_trim_right(s);
515+
return s;
516+
}
517+
#define mstr_trim(S) (mstr_trim)(mstr_view_from(S))
518+
444519
/**
445520
* @brief Split a single string view into two strings at the given position
446521
*

src/common/tests/test-mlib.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,14 @@ _test_str_view(void)
920920
// But "Food" > "foo" when case-insensitive:
921921
mlib_check(mstr_latin_casecmp(mstr_cstring("Food"), >, mstr_cstring("foo")));
922922
}
923+
924+
// Trimming
925+
{
926+
mstr_view s = mstr_cstring(" foo bar \n");
927+
mlib_check(mstr_cmp(mstr_trim_left(s), ==, mstr_cstring("foo bar \n")));
928+
mlib_check(mstr_cmp(mstr_trim_right(s), ==, mstr_cstring(" foo bar")));
929+
mlib_check(mstr_cmp(mstr_trim(s), ==, mstr_cstring("foo bar")));
930+
}
923931
}
924932

925933
static inline void
@@ -1226,7 +1234,7 @@ _test_int_vec(void)
12261234
int_vec_erase(&ints, ints.data + 1, ints.data + 3);
12271235
mlib_check(ints.size, eq, 2, because, "We erased two elements");
12281236

1229-
mlib_check(mlib_vec_at(ints, -1), eq, -7, because, "Negative index wraps");
1237+
mlib_check(mlib_vec_at(ints, -1), eq, 1729, because, "Negative index wraps");
12301238

12311239
int_vec_destroy(&ints);
12321240
}

0 commit comments

Comments
 (0)