19#include <CoreFoundation/CoreFoundation.h>
43 template<std::
integral T> [[nodiscard]] std::optional<T>
stringTo(std::string_view s);
48 template<
int BASE, std::
integral T> [[nodiscard]] std::optional<T>
stringToBase(std::string_view s);
52 [[nodiscard]] std::string
toLower(std::string_view str);
54 void trimRight(std::string& str,
const char* chars);
55 void trimRight(std::string& str,
char chars);
56 void trimRight(std::string_view& str, std::string_view chars);
57 void trimRight(std::string_view& str,
char chars);
58 void trimLeft (std::string& str,
const char* chars);
59 void trimLeft (std::string& str,
char chars);
60 void trimLeft (std::string_view& str, std::string_view chars);
61 void trimLeft (std::string_view& str,
char chars);
62 void trim (std::string_view& str, std::string_view chars);
63 void trim (std::string_view& str,
char chars);
65 [[nodiscard]] std::pair<std::string_view, std::string_view>
splitOnFirst(
66 std::string_view str, std::string_view chars);
67 [[nodiscard]] std::pair<std::string_view, std::string_view>
splitOnFirst(
68 std::string_view str,
char chars);
69 [[nodiscard]] std::pair<std::string_view, std::string_view>
splitOnLast(
70 std::string_view str, std::string_view chars);
71 [[nodiscard]] std::pair<std::string_view, std::string_view>
splitOnLast(
72 std::string_view str,
char chars);
74 unsigned min,
unsigned max);
82 template<EmptyParts keepOrRemove = EmptyParts::KEEP,
typename Separators>
83 [[nodiscard]]
inline auto split_view(std::string_view str, Separators separators) {
87 using value_type = std::string_view;
88 using difference_type = ptrdiff_t;
91 Iterator(
const Iterator&) =
default;
92 Iterator& operator=(
const Iterator&) =
default;
94 Iterator(std::string_view str_, Separators separators_)
95 : str(str_), separators(separators_) {
96 str.remove_prefix(skipSeparators(0));
100 [[nodiscard]] value_type
operator*()
const {
101 difference_type dummy; (void)dummy;
102 return {str.data(), p};
105 Iterator& operator++() {
106 if (p < str.size()) {
107 str.remove_prefix(skipSeparators(p + 1));
114 Iterator operator++(
int) {
auto copy = *
this; ++(*this);
return copy; }
116 [[nodiscard]]
bool operator==(
const Iterator&)
const =
default;
117 [[nodiscard]]
bool operator==(Sentinel)
const {
return str.empty(); }
120 static bool isSeparator(
char c,
char separators) {
121 return c == separators;
123 static bool isSeparator(
char c, std::string_view separators) {
124 return separators.find(c) != std::string_view::npos;
129 while ((p < str.size()) && !isSeparator(str[p], separators)) ++p;
132 std::string_view::size_type skipSeparators(std::string_view::size_type pos)
const {
133 if (keepOrRemove == EmptyParts::REMOVE) {
134 while ((pos < str.size()) && isSeparator(str[pos], separators)) ++pos;
140 std::string_view str;
141 std::string_view::size_type p;
142 Separators separators;
144 static_assert(std::forward_iterator<Iterator>);
145 static_assert(std::sentinel_for<Sentinel, Iterator>);
148 std::string_view str;
149 Separators separators;
151 [[nodiscard]]
auto begin()
const {
return Iterator{str, separators}; }
152 [[nodiscard]]
auto end()
const {
return Sentinel{}; }
155 return Splitter{str, separators};
160 [[nodiscard]]
bool operator()(std::string_view s1, std::string_view s2)
const {
161 auto m = std::min(s1.size(), s2.size());
162 int r = strncasecmp(s1.data(), s2.data(), m);
163 return (r != 0) ? (r < 0) : (s1.size() < s2.size());
168 [[nodiscard]]
bool operator()(std::string_view s1, std::string_view s2)
const {
169 auto m = std::min(s1.size(), s2.size());
170 int r = strncasecmp(s1.data(), s2.data(), m);
171 return (r != 0) ? (r > 0) : (s1.size() > s2.size());
175 [[nodiscard]]
bool operator()(std::string_view s1, std::string_view s2)
const {
176 if (s1.size() != s2.size())
return false;
177 return strncasecmp(s1.data(), s2.data(), s1.size()) == 0;
183 return std::search(haystack.begin(), haystack.end(),
184 needle.begin(), needle.end(),
185 [](
char x,
char y) { return toupper(x) == toupper(y); })
189#if defined(__APPLE__)
190 [[nodiscard]] std::string fromCFString(CFStringRef str);
193 template<
int BASE, std::
integral T>
198 auto e = s.data() + s.size();
199 if (
auto [p, ec] = std::from_chars(b, e, result, BASE);
200 (ec == std::errc()) && (p == e)) {
206 template<std::
integral T>
207 [[nodiscard]] std::optional<T>
stringTo(std::string_view s)
209 if (s.empty()) [[unlikely]]
return {};
210 if constexpr (std::is_signed_v<T>) {
212 if (s[0] ==
'-') [[unlikely]] {
217 using U = std::make_unsigned_t<T>;
218 auto tmp = stringTo<U>(s);
219 if (!tmp) [[unlikely]]
return {};
221 U max = U(std::numeric_limits<T>::max()) + 1;
222 if (negate) [[unlikely]] {
223 if (*tmp > max) [[unlikely]]
return {};
226 if (*tmp >= max) [[unlikely]]
return {};
230 if (s[0] !=
'0') [[likely]] {
231 return stringToBase<10, T>(s);
233 if (s.size() == 1)
return T(0);
234 if ((s[1] ==
'x') || (s[1] ==
'X')) [[likely]] {
236 return stringToBase<16, T>(s);
237 }
else if ((s[1] ==
'b') || (s[1] ==
'B')) {
239 return stringToBase<2, T>(s);
241 return stringToBase<10, T>(s);
void trim(string_view &str, string_view chars)
IterableBitSet< 64 > parseRange(string_view str, unsigned min, unsigned max)
bool stringToBool(string_view str)
std::optional< T > stringToBase(std::string_view s)
As above, but without dynamic base detection.
std::pair< string_view, string_view > splitOnLast(string_view str, string_view chars)
void trimRight(string &str, const char *chars)
std::optional< T > stringTo(std::string_view s)
Convert a string to an integral type 'T' (int, uint64_t, ...).
std::pair< string_view, string_view > splitOnFirst(string_view str, string_view chars)
void trimLeft(string &str, const char *chars)
std::string toLower(std::string_view str)
bool containsCaseInsensitive(std::string_view haystack, std::string_view needle)
auto split_view(std::string_view str, Separators separators)
bool operator()(std::string_view s1, std::string_view s2) const
bool operator()(std::string_view s1, std::string_view s2) const
bool operator()(std::string_view s1, std::string_view s2) const
constexpr uint128 operator*(const uint128 &a, const uint128 &b)
constexpr bool operator==(const zstring_view &x, const zstring_view &y)
constexpr auto begin(const zstring_view &x)
constexpr auto end(const zstring_view &x)