string: add upper
comparator
This commit is contained in:
parent
f9aa13ad81
commit
654f391cba
55
string.hpp
55
string.hpp
@ -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>;
|
||||
}
|
||||
|
@ -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 ();
|
||||
}
|
Loading…
Reference in New Issue
Block a user