| // SPDX-License-Identifier: Apache-2.0 |
| // Copyright Apache Software Foundation 2019 |
| /** @file |
| |
| Class for handling "views" of a buffer. Views presume the memory for the |
| buffer is managed elsewhere and allow efficient access to segments of the |
| buffer without copies. Views are read only as the view doesn't own the |
| memory. Along with generic buffer methods are specialized methods to support |
| better string parsing, particularly token based parsing. |
| */ |
| |
| #include "swoc/TextView.h" |
| #include <cctype> |
| #include <sstream> |
| |
| int |
| memcmp(std::string_view const &lhs, std::string_view const &rhs) |
| { |
| int zret = 0; |
| size_t n = rhs.size(); |
| |
| // Seems a bit ugly but size comparisons must be done anyway to get the memcmp args. |
| if (lhs.size() < rhs.size()) { |
| zret = 1; |
| n = lhs.size(); |
| } else if (lhs.size() > rhs.size()) { |
| zret = -1; |
| } else if (lhs.data() == rhs.data()) { // same memory, obviously equal. |
| return 0; |
| } |
| |
| int r = ::memcmp(lhs.data(), rhs.data(), n); |
| return r ? r : zret; |
| } |
| |
| int |
| strcasecmp(const std::string_view &lhs, const std::string_view &rhs) |
| { |
| int zret = 0; |
| size_t n = rhs.size(); |
| |
| // Seems a bit ugly but size comparisons must be done anyway to get the @c strncasecmp args. |
| if (lhs.size() < rhs.size()) { |
| zret = 1; |
| n = lhs.size(); |
| } else if (lhs.size() > rhs.size()) { |
| zret = -1; |
| } else if (lhs.data() == rhs.data()) { // the same memory, obviously equal. |
| return 0; |
| } |
| |
| int r = ::strncasecmp(lhs.data(), rhs.data(), n); |
| |
| return r ? r : zret; |
| } |
| |
| namespace swoc { inline namespace SWOC_VERSION_NS { |
| |
| /// @cond INTERNAL_DETAIL |
| const int8_t svtoi_convert[256] = { |
| /* [can't do this nicely because clang format won't allow exdented comments] |
| 0 1 2 3 4 5 6 7 8 9 A B C D E F |
| */ |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 00 |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10 |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 20 |
| 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 30 |
| -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 40 |
| 25, 26, 27, 28, 20, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 50 |
| -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 60 |
| 25, 26, 27, 28, 20, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 70 |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 80 |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 90 |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // A0 |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // B0 |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // C0 |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // D0 |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // E0 |
| -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // F0 |
| }; |
| /// @endcond |
| |
| intmax_t |
| svtoi(TextView src, TextView *out, int base) { |
| intmax_t zret = 0; |
| |
| if (src.ltrim_if(&isspace) && src) { |
| TextView parsed; |
| const char *start = src.data(); |
| bool neg = false; |
| if ('-' == *src) { |
| ++src; |
| neg = true; |
| } else if ('+' == *src) { |
| ++src; |
| } |
| zret = intmax_t(svtou(src, &parsed, base)); |
| if (!parsed.empty()) { |
| if (out) { |
| out->assign(start, parsed.data_end()); |
| } |
| if (neg) { |
| zret = -zret; |
| } |
| } |
| } |
| return zret; |
| } |
| |
| uintmax_t |
| svtou(TextView src, TextView *out, int base) { |
| uintmax_t zret = 0; |
| |
| if (out) { |
| out->clear(); |
| } |
| if (!(0 <= base && base <= 36)) { |
| return 0; |
| } |
| if (src.ltrim_if(&isspace).size()) { |
| auto origin = src.data(); |
| int8_t v; |
| // If base is 0, it wasn't specified - check for standard base prefixes |
| if (0 == base) { |
| base = 10; |
| if ('0' == *src) { |
| ++src; |
| base = 8; |
| if (src && ('x' == *src || 'X' == *src)) { |
| ++src; |
| base = 16; |
| } |
| } |
| } |
| |
| // For performance in common cases, use the templated conversion. |
| switch (base) { |
| case 8:zret = svto_radix<8>(src); |
| break; |
| case 10:zret = svto_radix<10>(src); |
| break; |
| case 16:zret = svto_radix<16>(src); |
| break; |
| default: |
| while (src.size() && (0 <= (v = svtoi_convert[static_cast<unsigned char>(*src)])) && |
| v < base) { |
| auto n = zret * base + v; |
| if (n < zret) { |
| zret = std::numeric_limits<uintmax_t>::max(); |
| break; // overflow, stop parsing. |
| } |
| zret = n; |
| ++src; |
| } |
| break; |
| } |
| |
| if (out) { |
| out->assign(origin, src.data()); |
| } |
| } |
| return zret; |
| } |
| |
| // Do the template instantiations. |
| template std::ostream& TextView::stream_write(std::ostream&, const TextView&) const; |
| |
| }} // namespace swoc |
| |
| namespace std |
| { |
| ostream & |
| operator<<(ostream &os, const swoc::TextView &b) |
| { |
| if (os.good()) { |
| b.stream_write<ostream>(os, b); |
| os.width(0); |
| } |
| return os; |
| } |
| } // namespace std |