string: add upper comparator

This commit is contained in:
Danny Robson 2019-05-02 11:03:22 +10:00
parent f9aa13ad81
commit 654f391cba
2 changed files with 91 additions and 2 deletions

View File

@ -8,6 +8,7 @@
#pragma once
#include "ascii.hpp"
#include "debug.hpp"
#include "view.hpp"
@ -216,3 +217,57 @@ namespace cruft {
}
};
}
namespace cruft::string::compare {
///////////////////////////////////////////////////////////////////////////
/// A case comparator that tests equality on a string after a
/// per-character transform is applied.
///
/// Neither string will be modified.
///
/// \tparam TransformV A character transform function
template <char (*TransformV)(char) noexcept>
struct transform {
template <
typename CharT,
typename = std::void_t<
typename std::char_traits<CharT>::char_type
>
>
bool operator() (cruft::view<CharT const *> a, cruft::view<CharT const*> b)
{
if (a.size () != b.size ())
return false;
for (auto i = a.begin (), j = b.begin (); i != a.end (); ++i, ++j)
if (TransformV (*i) != TransformV (*j))
return false;
return true;
}
template <
typename CharT,
typename = std::void_t<
typename std::char_traits<CharT>::char_type
>
>
bool operator() (CharT const *a, CharT const *b) const noexcept
{
auto const *i = a;
auto const *j = b;
for ( ; *i && *j; ++i, ++j)
if (TransformV (*i) != TransformV (*j))
return false;
// Ensure we've reached the ends of both strings
return !*i && !*j;
}
};
using lower = transform<ascii::try_lower>;
using upper = transform<ascii::try_upper>;
}

View File

@ -144,7 +144,7 @@ test_contains (cruft::TAP::logger &tap)
///////////////////////////////////////////////////////////////////////////////
void test_comparator (cruft::TAP::logger &tap)
void test_comparator_less (cruft::TAP::logger &tap)
{
cruft::string_less cmp;
@ -164,6 +164,39 @@ void test_comparator (cruft::TAP::logger &tap)
}
///////////////////////////////////////////////////////////////////////////////
void test_comparator_lower (cruft::TAP::logger &tap)
{
struct {
char const *a;
char const *b;
bool equal;
char const *message;
} const TESTS[] = {
{ "a", "a", true, "both single lower" },
{ "a", "A", true, "lower, upper singles" },
{ "A", "a", true, "upper, lower singles" },
{ "AbcDEf", "aBcdEF", true, "mixed upper lower" },
{ "A", "aa", false, "mixed case, different lengths" },
};
cruft::string::compare::lower cmp;
for (auto const &t: TESTS) {
tap.expect_eq (cmp (t.a, t.b), t.equal, "compare::lower, pointers, %!", t.message);
tap.expect_eq (
cmp (
cruft::view (t.a),
cruft::view (t.b)
),
t.equal,
"compare::lower, views, %!",
t.message
);
}
}
///////////////////////////////////////////////////////////////////////////////
int
main (int, char**)
@ -173,7 +206,8 @@ main (int, char**)
test_tokeniser (tap);
test_position (tap);
test_contains (tap);
test_comparator (tap);
test_comparator_less (tap);
test_comparator_lower (tap);
return tap.status ();
}