/* * This source code is released into the public domain. */ #ifndef LFJAIL_STRING_UTILS_HH #define LFJAIL_STRING_UTILS_HH #include #include #include #include #include "ctype.hh" namespace lfjail { /* * Remove leading whitespace from the given string_view. */ template std::basic_string_view skipws(std::basic_string_view text) { auto isspace = ctype_is(std::ctype_base::space); auto first_nonws = std::ranges::find_if_not(text, isspace); return {first_nonws, end(text)}; } template void skipws(std::basic_string_view *text) { auto ret = skipws(*text); *text = ret; } /* * Split a string on a predicate. Specifically, divide the string into two * strings at the first character where the predicate matches, and return * both strings. If the predicate matched, the matching character will be * discarded. */ template::iterator> Pred> std::pair, std::basic_string_view> split(std::basic_string_view text, Pred pred) { auto split_point = std::ranges::find_if(text, pred); if (split_point == end(text)) return {text, {}}; else return {{begin(text), split_point}, {std::next(split_point), end(text)}}; } template::iterator> Pred> std::basic_string_view split(std::basic_string_view *text, Pred pred) { auto [str, rest] = split(*text, pred); *text = rest; return str; } /* * Return the next word from a string_view. The by-value version returns * a pair, while the pointer version returns next-word * and sets the input string to remainder. */ template std::pair, std::basic_string_view> next_word(std::basic_string_view text) { return (split(skipws(text), ctype_is(std::ctype_base::space))); } template std::basic_string_view next_word(std::basic_string_view *text) { skipws(text); return (split(text, ctype_is(std::ctype_base::space))); } } // namespace lfjail #endif // LFJAIL_STRING_UTILS_HH