31#pragma GCC diagnostic push
32#pragma GCC diagnostic ignored "-Warray-bounds"
35namespace swoc {
inline namespace SWOC_VERSION_NS {
69 std::bitset<std::numeric_limits<unsigned char>::max() + 1> _chars;
96 using super_type = std::string_view;
105 constexpr
TextView(super_type const &that) noexcept;
115 constexpr
TextView(
char const *ptr,
size_t n) noexcept;
122 constexpr
TextView(
char const *ptr,
unsigned n) noexcept;
132 constexpr
TextView(
char const *ptr, ssize_t n) noexcept;
142 constexpr
TextView(
char const *ptr,
int n) noexcept;
166 template <typename T>
169 std::enable_if_t<!
std::is_array_v<T> &&
std::is_pointer_v<T> &&
std::is_convertible_v<T,
char const *>, T> last) noexcept
170 : super_type(first, last - first) {}
180 template <typename C, typename = std::enable_if_t<std::is_convertible_v<decltype(std::declval<C>().data()),
char const *> &&
181 std::is_convertible_v<
decltype(std::declval<C>().size()),
size_t>,
195 template <
size_t N>
constexpr TextView(
const char (&s)[N])
noexcept;
205 TextView(
char *&src) : super_type(src, src ? strlen(src) : 0) {}
215 TextView(
char const *&src) : super_type(src, src ? strlen(src) : 0) {}
232 template <
size_t N> self_type &
operator=(
const char (&s)[N]);
268 self_type &
assign(
char const *ptr,
size_t n);
276 self_type &
assign(
char const *b,
char const *e);
291 template <
size_t N> self_type &
assign(
const char (&s)[N])
noexcept;
301 template <typename C, typename = std::enable_if_t<std::is_convertible_v<decltype(std::declval<C>().
data()),
char const *> &&
302 std::is_convertible_v<
decltype(std::declval<C>().size()),
size_t>,
304 constexpr self_type &
306 return this->
assign(c.data(), c.size());
344 explicit constexpr operator
bool() const noexcept;
350 template <typename F>
size_t find_if(F const &pred) const;
352 template <typename F>
size_t rfind_if(F const &pred) const;
370 self_type &
ltrim(
std::string_view const &delimiters);
378 self_type &
ltrim(const
char *delimiters);
384 template <typename F> self_type &
ltrim_if(F const &pred);
401 self_type &
rtrim(
std::string_view const &delimiters);
409 template <typename F> self_type &
rtrim_if(F const &pred);
425 self_type &
trim(
std::string_view const &delimiters);
431 self_type &
trim(const
char *delimiters);
437 template <typename F> self_type &
trim_if(F const &pred);
444 constexpr self_type
prefix(
size_t n) const noexcept;
478 template <typename F> self_type
prefix_if(F const &pred) const;
654 constexpr self_type
suffix(
size_t n) const noexcept;
688 template <typename F> self_type
suffix_if(F const &pred) const;
846 constexpr self_type
substr(size_type pos = 0, size_type count = npos) const noexcept;
949 operator()(self_type
const &lhs, self_type
const &rhs)
const noexcept {
950 return -1 ==
strcmp(lhs, rhs);
958 operator()(self_type
const &lhs, self_type
const &rhs)
const noexcept {
967 operator()(self_type
const &lhs, self_type
const &rhs)
const noexcept {
968 return lhs.size() == rhs.size() && 0 ==
strcasecmp(lhs, rhs);
981 constexpr value_type
const *
data() const noexcept;
990 constexpr value_type const *
data_end() const noexcept;
1002 constexpr self_type
prefix(
int n) const noexcept;
1005 constexpr self_type
suffix(
int n) const noexcept;
1060 static_assert(1 <= RADIX && RADIX <= 36,
"Radix must be in the range 2..36");
1061 static constexpr auto MAX = std::numeric_limits<uintmax_t>::max();
1062 static constexpr auto OVERFLOW_LIMIT = MAX / RADIX;
1068 if (zret <= OVERFLOW_LIMIT && v <= (MAX - (zret *= RADIX)) ) {
1106 for (
auto c : chars) {
1107 _chars[uint8_t(c)] =
true;
1118 return _chars[uint8_t(c)];
1127 : super_type(ptr, n == npos ? (ptr ? ::strlen(ptr) : 0) : n) {}
1128inline constexpr TextView::TextView(
const char *ptr,
unsigned n) noexcept : super_type(ptr,
size_t(n)) {}
1130 : super_type(ptr, n < 0 ? (ptr ? ::strlen(ptr) : 0) :
size_t(n)) {}
1132 : super_type(ptr, n < 0 ? (ptr ? ::strlen(ptr) : 0) :
size_t(n)) {}
1133inline constexpr TextView::TextView(std::nullptr_t) noexcept : super_type(
nullptr, 0) {}
1135inline constexpr TextView::TextView(super_type
const &that) noexcept : super_type(that) {}
1136template <
size_t N>
constexpr TextView::TextView(
const char (&s)[N]) noexcept : super_type(s, s[N - 1] ? N : N - 1) {}
1137template <
typename C,
typename>
constexpr TextView::TextView(C
const &c) : super_type(c.data(), c.size()) {}
1142 for (
char c : delimiters)
1143 set[
static_cast<uint8_t
>(c)] =
true;
1148 new (
this) self_type();
1152inline constexpr char
1154 return this->empty() ? char(0) : *(this->
data());
1157inline constexpr bool
1159 return this->empty();
1162inline constexpr TextView::operator bool() const noexcept {
1163 return !this->empty();
1168 this->remove_prefix(1);
1174 self_type zret{*
this};
1175 this->remove_prefix(1);
1181 this->remove_prefix(n);
1188 return *
this = self_type{s, s[N - 1] ? N : N - 1};
1193 this->super_type::operator=(that);
1199 this->super_type::operator=(s);
1205 this->super_type::operator=(s);
1211 this->super_type::operator=(s);
1217 return this->assign(c_str, strlen(c_str));
1222 return this->assign(c_str, strlen(c_str));
1227 *
this = super_type(s);
1233 *
this = super_type(ptr, n == npos ? (ptr ? ::strlen(ptr) : 0) : n);
1239 *
this = super_type(b, e - b);
1246 return *
this = self_type{s, s[N - 1] ? N : N - 1};
1249inline constexpr auto
1251 return {this->data(), std::min(n, this->size())};
1256 return {this->data(), std::min<size_t>(n, this->size())};
1262 if (
auto n = this->find(c); n != npos) {
1263 zret.assign(this->data(), n);
1271 if (
auto n = this->find_first_of(delimiters); n != npos) {
1272 zret.assign(this->
data(), n);
1277template <
typename F>
1281 if (
auto n = this->find_if(pred); n != npos) {
1282 zret.assign(this->data(), n);
1289 this->super_type::remove_prefix(std::min(n, this->size()));
1295 if (
auto n = this->find(c); n != npos) {
1296 this->super_type::remove_prefix(n + 1);
1303 if (
auto n = this->find_first_of(delimiters); n != npos) {
1304 this->super_type::remove_prefix(n + 1);
1309template <
typename F>
1312 if (
auto n = this->find_if(pred); n != npos) {
1313 this->super_type::remove_prefix(n + 1);
1321 if (n < this->size()) {
1340 return this->
split_prefix(this->find_first_of(delimiters));
1343template <
typename F>
1351 n = std::min(n, this->size());
1352 self_type zret = this->
prefix(n);
1364 return this->
take_prefix(this->find_first_of(delimiters));
1367template <
typename F>
1370 return this->take_prefix(this->find_if(pred));
1375 n = std::min(n, this->size());
1376 return {this->data_end() - n, n};
1381 return this->suffix(
size_t(n));
1387 if (
auto n = this->rfind(c); n != npos && n + 1 < this->size()) {
1389 zret.assign(this->
data() + n, this->size() - n);
1397 if (
auto n = this->find_last_of(delimiters); n != npos) {
1399 zret.assign(this->
data() + n, this->size() - n);
1404template <
typename F>
1408 if (
auto n = this->rfind_if(pred); n != npos) {
1410 zret.assign(this->data() + n, this->size() - n);
1417 this->super_type::remove_suffix(std::min(n, this->size()));
1423 if (
auto n = this->rfind(c); n != npos) {
1426 return this->
clear();
1431 if (
auto n = this->find_last_of(delimiters); n != npos) {
1434 return this->
clear();
1437template <
typename F>
1438TextView::self_type &
1440 if (
auto n = this->
rfind_if(pred); n != npos) {
1443 return this->
clear();
1449 n = std::min(n, this->size());
1457 return this->split_suffix(
size_t(n));
1462 auto idx = this->rfind(c);
1463 return npos == idx ? self_type{} : this->
split_suffix(this->size() - (idx + 1));
1468 auto idx = this->find_last_of(delimiters);
1469 return npos == idx ? self_type{} : this->split_suffix(this->size() - (idx + 1));
1472template <
typename F>
1480 self_type zret{*
this};
1497 return this->
take_suffix(this->find_last_of(delimiters));
1500template <
typename F>
1506template <
typename F>
1509 for (
const char *spot = this->
data(), *limit = this->
data_end(); spot < limit; ++spot)
1511 return spot - this->
data();
1515template <
typename F>
1518 for (
const char *spot = this->
data_end(), *limit = this->
data(); spot > limit;)
1520 return spot - this->
data();
1532 auto n = this->find_last_not_of(c);
1533 this->
remove_suffix(this->size() - (n == npos ? 0 : n + 1));
1544 const char *spot = this->
data();
1545 const char *limit = this->
data_end();
1547 while (spot < limit && delimiters(*spot)) {
1557 return this->
ltrim(CharSet(delimiters));
1562 return this->
ltrim(CharSet(delimiters));
1567 const char *spot = this->
data_end();
1568 const char *limit = this->
data();
1569 while (limit < spot-- && delimiters(*spot)) {
1578 return this->
rtrim(CharSet(delimiters));
1587 for (spot = this->
data(), limit = this->
data_end(); spot < limit && delimiters(*spot); ++spot)
1592 limit = this->
data();
1593 while (limit < spot-- && delimiters(*spot)) {
1602 return this->
trim(CharSet(delimiters));
1607 return this->
trim(CharSet(delimiters));
1610template <
typename F>
1611TextView::self_type &
1615 for (spot = this->
data(), limit = this->
data_end(); spot < limit && pred(*spot); ++spot)
1621template <
typename F>
1622TextView::self_type &
1624 const char *spot = this->
data_end();
1625 const char *limit = this->
data();
1626 while (limit < spot-- && pred(*spot))
1632template <
typename F>
1633TextView::self_type &
1638constexpr inline auto
1640 return super_type::data();
1643constexpr inline auto
1645 return this->
data() + this->size();
1650 if (pos >= this->size()) {
1653 count = std::min(this->size() - pos, count);
1654 return {this->data() + pos, count};
1659 return this->size() >= prefix.size() && 0 == ::memcmp(this->data(), prefix.data(), prefix.size());
1673 return !this->empty() && c == this->front();
1677 return !this->empty() && tolower(c) == tolower(this->front());
1682 return this->size() >= prefix.size() && 0 == ::strncasecmp(this->data(), prefix.data(), prefix.size());
1687 return this->size() >= suffix.size() && 0 == ::memcmp(this->data_end() - suffix.size(), suffix.data(), suffix.size());
1692 return this->size() >= suffix.size() && 0 == ::strncasecmp(this->data_end() - suffix.size(), suffix.data(), suffix.size());
1707 return !this->empty() && c == this->back();
1711 return !this->empty() && tolower(c) == tolower(this->back());
1714template <
typename Stream>
1718 static const auto stream_fill = [](Stream &ostream,
size_t n) -> Stream & {
1719 static constexpr size_t pad_size = 8;
1720 typename Stream::char_type padding[pad_size];
1722 std::fill_n(padding, pad_size, ostream.fill());
1723 for (; n >= pad_size && ostream.good(); n -= pad_size)
1724 ostream.write(padding, pad_size);
1725 if (n > 0 && ostream.good())
1726 ostream.write(padding, n);
1730 const std::size_t w = os.width();
1731 if (w <= b.size()) {
1732 os.write(b.
data(), b.size());
1734 const std::size_t pad_size = w - b.size();
1735 const bool align_left = (os.flags() & Stream::adjustfield) == Stream::left;
1736 if (!align_left && os.good())
1737 stream_fill(os, pad_size);
1739 os.write(b.
data(), b.size());
1740 if (align_left && os.good())
1741 stream_fill(os, pad_size);
1746template <
typename F>
1750 for (
auto spot = this->
data(), limit = spot + this->size(); spot < limit && pred(*spot); ++spot, ++idx)
1757template <
typename F>
1760 size_t idx = this->size() - 1;
1761 for (
auto spot = this->
data() + idx, limit = this->
data(); spot >= limit && pred(*spot); --spot, --idx)
1801 using source_iterator =
decltype(V{}.begin());
1806 using source_value_type = std::remove_reference_t<
decltype(*source_iterator{})>;
1808 using value_type = std::invoke_result_t<transform_type, source_value_type>;
1851 explicit operator bool()
const;
1873template <
typename X,
typename V>
1876template <
typename X,
typename V>
1880template <
typename X,
typename V>
1886template <
typename X,
typename V>
1893template <
typename X,
typename V>
1896 self_type zret{*
this};
1901template <
typename X,
typename V>
1911template <
typename X,
typename V>
1917template <
typename X,
typename V>
1931template <
typename X,
typename V>
1947 using source_iterator =
decltype(V{}.begin());
1951 using source_value_type = std::remove_reference_t<
decltype(*source_iterator{})>;
1974 bool operator==(self_type
const &that)
const;
1976 bool operator!=(self_type
const &that)
const;
1991 explicit operator bool()
const;
2006template <
typename V>
2012template <
typename V>
2019template <
typename V>
2027template <
typename V>
2033template <
typename V>
2039template <
typename V>
2049template <
typename V>
2055template <
typename V>
2058 return self_type{
_limit};
2063template <
typename V>
2087constexpr std::string_view
2088operator"" _sv(
const char *s,
size_t n) {
2103operator"" _tv(
const char *s,
size_t n) {
2120template <>
struct iterator_traits<swoc::TextView> {
2121 using value_type = char;
2122 using pointer_type =
const char *;
2123 using reference_type =
const char &;
2124 using difference_type = ssize_t;
2125 using iterator_category = forward_iterator_tag;
2128template <
typename X,
typename V>
struct iterator_traits<swoc::TransformView<X, V>> {
2130 using pointer_type =
const value_type *;
2131 using reference_type =
const value_type &;
2132 using difference_type = ssize_t;
2133 using iterator_category = forward_iterator_tag;
2137 static constexpr hash<string_view> super_hash{};
2139 operator()(swoc::TextView
const &s)
const {
2140 return super_hash(s);
2148#pragma GCC diagnostic pop
constexpr TextView() noexcept=default
Default constructor (empty buffer).
constexpr value_type const * data() const noexcept
constexpr CharSet(TextView const &chars)
bool operator()(unsigned char c) const
self_type & operator=(char *&s)
Assign from C-string s.
self_type take_suffix_at(char c)
self_type prefix_at(char c) const
constexpr bool operator!() const noexcept
self_type & trim_if(F const &pred)
self_type & remove_suffix_if(F const &pred)
self_type take_suffix_if(F const &pred)
bool starts_with_nocase(std::string_view const &prefix) const noexcept
self_type & clear()
Clear the view (become an empty view).
self_type & assign(char *&c_str)
self_type clip_prefix_of(F const &pred)
constexpr self_type & assign(C const &c)
self_type & remove_prefix_at(char c)
self_type & rtrim_if(F const &pred)
constexpr TextView() noexcept=default
Default constructor (empty buffer).
self_type take_suffix(size_t n)
Stream & stream_write(Stream &os, const TextView &b) const
static void init_delimiter_set(std::string_view const &delimiters, std::bitset< 256 > &set)
Initialize a bit mask to mark which characters are in this view.
self_type & remove_prefix_if(F const &pred)
self_type operator++(int)
constexpr char operator*() const
self_type & remove_prefix(size_t n)
TextView(char const *&src)
self_type & operator=(char const *&s)
Assign from C-string s.
self_type split_prefix_if(F const &pred)
self_type & ltrim_if(F const &pred)
constexpr value_type const * data_end() const noexcept
bool ends_with_nocase(std::string_view const &suffix) const noexcept
self_type & rtrim(char c)
self_type & assign(std::string const &s)
Explicitly set the view from a std::string.
TextView(std::string const &str) noexcept
self_type & assign(char const *&c_str)
self_type split_prefix(size_t n)
self_type & operator+=(size_t n)
bool ends_with(std::string_view const &suffix) const noexcept
constexpr self_type prefix(size_t n) const noexcept
self_type & remove_suffix_at(char c)
bool starts_with(std::string_view const &prefix) const noexcept
self_type take_prefix_at(char c)
self_type & remove_suffix(size_t n)
self_type split_suffix_if(F const &pred)
self_type split_prefix_at(char c)
self_type & assign(const char(&s)[N]) noexcept
self_type split_suffix_at(char c)
self_type take_prefix(size_t n)
self_type & assign(char const *ptr, size_t n)
constexpr TextView(const char(&s)[N]) noexcept
self_type suffix_at(char c) const
self_type & operator=(const char(&s)[N])
self_type & operator=(super_type const &that)
Assign a super class instance, std::string_view to this.
constexpr value_type const * data() const noexcept
constexpr self_type suffix(size_t n) const noexcept
self_type & ltrim(char c)
self_type suffix_if(F const &pred) const
constexpr TextView(std::nullptr_t) noexcept
self_type take_prefix_if(F const &pred)
constexpr self_type substr(size_type pos=0, size_type count=npos) const noexcept
self_type clip_suffix_of(F const &pred)
size_t rfind_if(F const &pred) const
Get the offset of the last character for which pred is true.
self_type & assign(char const *b, char const *e)
self_type prefix_if(F const &pred) const
size_t find_if(F const &pred) const
Get the offset of the first character for which pred is true.
self_type & operator=(const std::string &s)
Assign from a std::string.
self_type split_suffix(size_t n)
constexpr TextView(C const &c)
For template deduction guides.
uintmax_t svtou(TextView src, TextView *out, int base)
uintmax_t svto_radix(TextView &src)
const int8_t svtoi_convert[256]
intmax_t svtoi(TextView src, TextView *out, int base)
TransformView< X, V > transform_view_of(X const &xf, V const &src)
bool operator==(IPAddr const &lhs, sockaddr const *sa)
Equality.
bool operator!=(IP4Addr const &lhs, IP4Addr const &rhs)
int strcasecmp(const std::string_view &lhs, const std::string_view &rhs)
int strcmp(const std::string_view &lhs, const std::string_view &rhs)
Support for containers that need case insensitive comparisons between views.
bool operator()(self_type const &lhs, self_type const &rhs) const noexcept
Ordering functor, case ignoring lexicographic comparison.
bool operator()(self_type const &lhs, self_type const &rhs) const noexcept
Ordering functor, lexicographic comparison.
bool operator()(self_type const &lhs, self_type const &rhs) const noexcept