src: Clean up string utlity functions

This commit is contained in:
Tatsuhiro Tsujikawa 2015-02-10 22:35:10 +09:00
parent 3e2714810a
commit 7fa62c9904
5 changed files with 213 additions and 157 deletions

View File

@ -123,8 +123,11 @@ int main(int argc, char *argv[]) {
!CU_add_test(pSuite, "util_inp_strlower",
shrpx::test_util_inp_strlower) ||
!CU_add_test(pSuite, "util_to_base64", shrpx::test_util_to_base64) ||
!CU_add_test(pSuite, "util_to_token68", shrpx::test_util_to_token68) ||
!CU_add_test(pSuite, "util_percent_encode_token",
shrpx::test_util_percent_encode_token) ||
!CU_add_test(pSuite, "util_percent_decode",
shrpx::test_util_percent_decode) ||
!CU_add_test(pSuite, "util_quote_string",
shrpx::test_util_quote_string) ||
!CU_add_test(pSuite, "util_utox", shrpx::test_util_utox) ||
@ -145,6 +148,8 @@ int main(int argc, char *argv[]) {
shrpx::test_util_duration_str) ||
!CU_add_test(pSuite, "util_format_duration",
shrpx::test_util_format_duration) ||
!CU_add_test(pSuite, "util_starts_with", shrpx::test_util_starts_with) ||
!CU_add_test(pSuite, "util_ends_with", shrpx::test_util_ends_with) ||
!CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) ||
!CU_add_test(pSuite, "buffer_write", nghttp2::test_buffer_write) ||
!CU_add_test(pSuite, "pool_recycle", nghttp2::test_pool_recycle) ||

View File

@ -123,6 +123,19 @@ std::string percent_encode_token(const std::string &target) {
return dest;
}
uint32_t hex_to_uint(char c) {
if (c <= '9') {
return c - '0';
}
if (c <= 'Z') {
return c - 'A' + 10;
}
if (c <= 'z') {
return c - 'a' + 10;
}
return c;
}
std::string percentDecode(std::string::const_iterator first,
std::string::const_iterator last) {
std::string result;
@ -130,15 +143,14 @@ std::string percentDecode(std::string::const_iterator first,
if (*first == '%') {
if (first + 1 != last && first + 2 != last && isHexDigit(*(first + 1)) &&
isHexDigit(*(first + 2))) {
std::string numstr(first + 1, first + 3);
result += strtol(numstr.c_str(), 0, 16);
result += (hex_to_uint(*(first + 1)) << 4) + hex_to_uint(*(first + 2));
first += 2;
} else {
result += *first;
continue;
}
} else {
result += *first;
continue;
}
result += *first;
}
return result;
}
@ -353,14 +365,6 @@ time_t parse_http_date(const std::string &s) {
return timegm(&tm);
}
bool startsWith(const std::string &a, const std::string &b) {
return startsWith(a.begin(), a.end(), b.begin(), b.end());
}
bool istartsWith(const std::string &a, const std::string &b) {
return istartsWith(a.begin(), a.end(), b.begin(), b.end());
}
namespace {
void streq_advance(const char **ap, const char **bp) {
for (; **ap && **bp && lowcase(**ap) == lowcase(**bp); ++*ap, ++*bp)
@ -376,24 +380,11 @@ bool istartsWith(const char *a, const char *b) {
return !*b;
}
bool istartsWith(const char *a, size_t n, const char *b) {
return istartsWith(a, a + n, b, b + strlen(b));
}
bool endsWith(const std::string &a, const std::string &b) {
return endsWith(a.begin(), a.end(), b.begin(), b.end());
}
bool strieq(const std::string &a, const std::string &b) {
if (a.size() != b.size()) {
return false;
}
for (size_t i = 0; i < a.size(); ++i) {
if (lowcase(a[i]) != lowcase(b[i])) {
return false;
}
}
return true;
return std::equal(std::begin(a), std::end(a), std::begin(b), CaseCmp());
}
bool strieq(const char *a, const char *b) {
@ -405,20 +396,6 @@ bool strieq(const char *a, const char *b) {
return !*a && !*b;
}
bool strieq(const char *a, const uint8_t *b, size_t bn) {
if (!a || !b) {
return false;
}
const uint8_t *blast = b + bn;
for (; *a && b != blast && lowcase(*a) == lowcase(*b); ++a, ++b)
;
return !*a && b == blast;
}
bool strieq(const char *a, const char *b, size_t bn) {
return strieq(a, reinterpret_cast<const uint8_t *>(b), bn);
}
int strcompare(const char *a, const uint8_t *b, size_t bn) {
assert(a && b);
const uint8_t *blast = b + bn;
@ -479,47 +456,38 @@ std::string format_hex(const unsigned char *s, size_t len) {
}
void to_token68(std::string &base64str) {
for (auto i = std::begin(base64str); i != std::end(base64str); ++i) {
switch (*i) {
std::transform(std::begin(base64str), std::end(base64str),
std::begin(base64str), [](char c) {
switch (c) {
case '+':
*i = '-';
break;
return '-';
case '/':
*i = '_';
break;
case '=':
base64str.erase(i, std::end(base64str));
return;
return '_';
default:
return c;
}
}
return;
});
base64str.erase(std::find(std::begin(base64str), std::end(base64str), '='));
}
void to_base64(std::string &token68str) {
for (auto i = std::begin(token68str); i != std::end(token68str); ++i) {
switch (*i) {
std::transform(std::begin(token68str), std::end(token68str),
std::begin(token68str), [](char c) {
switch (c) {
case '-':
*i = '+';
break;
return '+';
case '_':
*i = '/';
break;
return '/';
default:
return c;
}
}
});
if (token68str.size() & 0x3) {
token68str.append(4 - (token68str.size() & 0x3), '=');
}
return;
}
void inp_strlower(std::string &s) {
for (auto i = std::begin(s); i != std::end(s); ++i) {
if ('A' <= *i && *i <= 'Z') {
*i = (*i) - 'A' + 'a';
}
}
}
namespace {
// Calculates DamerauLevenshtein distance between c-string a and b
// with given costs. swapcost, subcost, addcost and delcost are cost

View File

@ -165,6 +165,10 @@ bool in_token(char c);
bool in_attr_char(char c);
// Returns integer corresponding to hex notation |c|. It is undefined
// if isHexDigit(c) is false.
uint32_t hex_to_uint(char c);
std::string percentEncode(const unsigned char *target, size_t len);
std::string percentEncode(const std::string &target);
@ -193,97 +197,8 @@ std::string iso8601_date(int64_t ms);
time_t parse_http_date(const std::string &s);
template <typename InputIterator1, typename InputIterator2>
bool startsWith(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2) {
if (last1 - first1 < last2 - first2) {
return false;
}
return std::equal(first2, last2, first1);
}
bool startsWith(const std::string &a, const std::string &b);
struct CaseCmp {
bool operator()(char lhs, char rhs) const {
if ('A' <= lhs && lhs <= 'Z') {
lhs += 'a' - 'A';
}
if ('A' <= rhs && rhs <= 'Z') {
rhs += 'a' - 'A';
}
return lhs == rhs;
}
};
template <typename InputIterator1, typename InputIterator2>
bool istartsWith(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2) {
if (last1 - first1 < last2 - first2) {
return false;
}
return std::equal(first2, last2, first1, CaseCmp());
}
bool istartsWith(const std::string &a, const std::string &b);
bool istartsWith(const char *a, const char *b);
bool istartsWith(const char *a, size_t n, const char *b);
template <typename InputIterator1, typename InputIterator2>
bool endsWith(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2) {
if (last1 - first1 < last2 - first2) {
return false;
}
return std::equal(first2, last2, last1 - (last2 - first2));
}
template <typename InputIterator1, typename InputIterator2>
bool iendsWith(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2) {
if (last1 - first1 < last2 - first2) {
return false;
}
return std::equal(first2, last2, last1 - (last2 - first2), CaseCmp());
}
bool endsWith(const std::string &a, const std::string &b);
int strcompare(const char *a, const uint8_t *b, size_t n);
bool strieq(const std::string &a, const std::string &b);
bool strieq(const char *a, const char *b);
bool strieq(const char *a, const uint8_t *b, size_t n);
bool strieq(const char *a, const char *b, size_t n);
template <typename A, typename B>
bool streq(const A *a, const B *b, size_t bn) {
if (!a || !b) {
return false;
}
auto blast = b + bn;
for (; *a && b != blast && *a == *b; ++a, ++b)
;
return !*a && b == blast;
}
template <typename A, typename B>
bool streq(const A *a, size_t alen, const B *b, size_t blen) {
if (alen != blen) {
return false;
}
return memcmp(a, b, alen) == 0;
}
bool strifind(const char *a, const char *b);
char upcase(char c);
char lowcase(char c);
inline char lowcase(char c) {
static unsigned char tbl[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
@ -308,8 +223,111 @@ inline char lowcase(char c) {
return tbl[static_cast<unsigned char>(c)];
}
template <typename InputIterator1, typename InputIterator2>
bool startsWith(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2) {
if (last1 - first1 < last2 - first2) {
return false;
}
return std::equal(first2, last2, first1);
}
inline bool startsWith(const std::string &a, const std::string &b) {
return startsWith(std::begin(a), std::end(a), std::begin(b), std::end(b));
}
struct CaseCmp {
bool operator()(char lhs, char rhs) const {
return lowcase(lhs) == lowcase(rhs);
}
};
template <typename InputIterator1, typename InputIterator2>
bool istartsWith(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2) {
if (last1 - first1 < last2 - first2) {
return false;
}
return std::equal(first2, last2, first1, CaseCmp());
}
inline bool istartsWith(const std::string &a, const std::string &b) {
return istartsWith(std::begin(a), std::end(a), std::begin(b), std::end(b));
}
template <typename InputIt>
bool istartsWith(InputIt a, size_t an, const char *b) {
return istartsWith(a, a + an, b, b + strlen(b));
}
bool istartsWith(const char *a, const char *b);
template <typename InputIterator1, typename InputIterator2>
bool endsWith(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2) {
if (last1 - first1 < last2 - first2) {
return false;
}
return std::equal(first2, last2, last1 - (last2 - first2));
}
inline bool endsWith(const std::string &a, const std::string &b) {
return endsWith(std::begin(a), std::end(a), std::begin(b), std::end(b));
}
template <typename InputIterator1, typename InputIterator2>
bool iendsWith(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2) {
if (last1 - first1 < last2 - first2) {
return false;
}
return std::equal(first2, last2, last1 - (last2 - first2), CaseCmp());
}
inline bool iendsWith(const std::string &a, const std::string &b) {
return iendsWith(std::begin(a), std::end(a), std::begin(b), std::end(b));
}
int strcompare(const char *a, const uint8_t *b, size_t n);
template <typename InputIt> bool strieq(const char *a, InputIt b, size_t bn) {
if (!a) {
return false;
}
auto blast = b + bn;
for (; *a && b != blast && lowcase(*a) == lowcase(*b); ++a, ++b)
;
return !*a && b == blast;
}
bool strieq(const std::string &a, const std::string &b);
bool strieq(const char *a, const char *b);
template <typename InputIt> bool streq(const char *a, InputIt b, size_t bn) {
if (!a) {
return false;
}
auto blast = b + bn;
for (; *a && b != blast && *a == *b; ++a, ++b)
;
return !*a && b == blast;
}
template <typename InputIt1, typename InputIt2>
bool streq(InputIt1 a, size_t alen, InputIt2 b, size_t blen) {
if (alen != blen) {
return false;
}
return std::equal(a, a + alen, b);
}
bool strifind(const char *a, const char *b);
// Lowercase |s| in place.
void inp_strlower(std::string &s);
inline void inp_strlower(std::string &s) {
std::transform(std::begin(s), std::end(s), std::begin(s), lowcase);
}
// Returns string representation of |n| with 2 fractional digits.
std::string dtos(double n);

View File

@ -66,6 +66,18 @@ void test_util_strieq(void) {
CU_ASSERT(util::strieq(std::string(), std::string()));
CU_ASSERT(!util::strieq(std::string("alpha"), std::string("AlPhA ")));
CU_ASSERT(!util::strieq(std::string(), std::string("AlPhA ")));
CU_ASSERT(util::strieq("alpha", "alpha", 5));
CU_ASSERT(util::strieq("alpha", "AlPhA", 5));
CU_ASSERT(util::strieq("", static_cast<const char *>(nullptr), 0));
CU_ASSERT(!util::strieq("alpha", "AlPhA ", 6));
CU_ASSERT(!util::strieq("", "AlPhA ", 6));
CU_ASSERT(util::strieq("alpha", "alpha"));
CU_ASSERT(util::strieq("alpha", "AlPhA"));
CU_ASSERT(util::strieq("", ""));
CU_ASSERT(!util::strieq("alpha", "AlPhA "));
CU_ASSERT(!util::strieq("", "AlPhA "));
}
void test_util_inp_strlower(void) {
@ -92,6 +104,16 @@ void test_util_to_base64(void) {
CU_ASSERT("AAA++B/B" == x);
}
void test_util_to_token68(void) {
std::string x = "AAA++B/=";
util::to_token68(x);
CU_ASSERT("AAA--B_" == x);
x = "AAA++B/B";
util::to_token68(x);
CU_ASSERT("AAA--B_B" == x);
}
void test_util_percent_encode_token(void) {
CU_ASSERT("h2" == util::percent_encode_token("h2"));
CU_ASSERT("h3~" == util::percent_encode_token("h3~"));
@ -99,6 +121,21 @@ void test_util_percent_encode_token(void) {
CU_ASSERT("http%202" == util::percent_encode_token("http 2"));
}
void test_util_percent_decode(void) {
{
std::string s = "%66%6F%6f%62%61%72";
CU_ASSERT("foobar" == util::percentDecode(std::begin(s), std::end(s)));
}
{
std::string s = "%66%6";
CU_ASSERT("f%6" == util::percentDecode(std::begin(s), std::end(s)));
}
{
std::string s = "%66%";
CU_ASSERT("f%" == util::percentDecode(std::begin(s), std::end(s)));
}
}
void test_util_quote_string(void) {
CU_ASSERT("alpha" == util::quote_string("alpha"));
CU_ASSERT("" == util::quote_string(""));
@ -277,4 +314,28 @@ void test_util_format_duration(void) {
util::format_duration(std::chrono::microseconds(1050000)));
}
void test_util_starts_with(void) {
CU_ASSERT(util::startsWith("foo", "foo"));
CU_ASSERT(util::startsWith("fooo", "foo"));
CU_ASSERT(util::startsWith("ofoo", ""));
CU_ASSERT(!util::startsWith("ofoo", "foo"));
CU_ASSERT(util::istartsWith("FOO", "fOO"));
CU_ASSERT(util::startsWith("ofoo", ""));
CU_ASSERT(util::istartsWith("fOOo", "Foo"));
CU_ASSERT(!util::istartsWith("ofoo", "foo"));
}
void test_util_ends_with(void) {
CU_ASSERT(util::endsWith("foo", "foo"));
CU_ASSERT(util::endsWith("foo", ""));
CU_ASSERT(util::endsWith("ofoo", "foo"));
CU_ASSERT(!util::endsWith("ofoo", "fo"));
CU_ASSERT(util::iendsWith("fOo", "Foo"));
CU_ASSERT(util::iendsWith("foo", ""));
CU_ASSERT(util::iendsWith("oFoo", "fOO"));
CU_ASSERT(!util::iendsWith("ofoo", "fo"));
}
} // namespace shrpx

View File

@ -31,7 +31,9 @@ void test_util_streq(void);
void test_util_strieq(void);
void test_util_inp_strlower(void);
void test_util_to_base64(void);
void test_util_to_token68(void);
void test_util_percent_encode_token(void);
void test_util_percent_decode(void);
void test_util_quote_string(void);
void test_util_utox(void);
void test_util_http_date(void);
@ -44,6 +46,8 @@ void test_util_parse_uint(void);
void test_util_parse_duration_with_unit(void);
void test_util_duration_str(void);
void test_util_format_duration(void);
void test_util_starts_with(void);
void test_util_ends_with(void);
} // namespace shrpx