0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-16 15:00:51 +01:00

ircd: Add stringops suite for globular expression matching.

This commit is contained in:
Jason Volk 2019-05-25 16:46:51 -07:00
parent 680734c47b
commit 8aa67ccb48
2 changed files with 117 additions and 0 deletions

View file

@ -21,6 +21,10 @@ namespace ircd
struct igreater;
struct iequals;
// Globular ('*' and '?') expression utils.
struct gmatch;
struct gequals;
// Vintage
struct strlcpy;
struct strlcat;
@ -296,6 +300,60 @@ const
});
}
/// Globular equals. This allows either side of the comparison to include '*'
/// and '?' characters and equality of the string expressions will be
/// determined.
struct ircd::gequals
{
using is_transparent = std::true_type;
bool s;
operator const bool &() const
{
return s;
}
bool operator()(const string_view &a, const string_view &b) const;
template<class A,
class B>
gequals(A&& a, B&& b)
:s{operator()(std::forward<A>(a), std::forward<B>(b))}
{}
gequals() = default;
};
/// Globular match. Similar to gequals but only one side of the comparison is
/// considered to be the expression with '*' and '?' characters. The expression
/// string is passed at construction. The comparison inputs are treated as
/// non-expression strings. This allows for greater optimization than gequals.
struct ircd::gmatch
{
string_view expr;
bool s;
operator const bool &() const
{
return s;
}
bool operator()(const string_view &a) const;
gmatch(const string_view &expr)
:expr{expr}
{}
template<class A>
gmatch(const string_view &expr, A&& a)
:expr{expr}
,s{operator()(std::forward<A>(a))}
{}
gmatch() = default;
};
inline ircd::string_view
ircd::trunc(const string_view &s,
const size_t &max)

View file

@ -452,3 +452,62 @@ ircd::replace(const string_view &s,
return std::distance(begin(buf), p);
});
}
//
// gequals
//
bool
ircd::gequals::operator()(const string_view &a, const string_view &b)
const
{
size_t ap(0), bp(0);
while(ap < a.size() && bp < b.size())
{
const auto ca(tolower(a.at(ap))), cb(tolower(b.at(bp)));
const auto globa(ca == '*'), globb(cb == '*');
const auto wilda(ca == '?'), wildb(cb == '?');
if(!globa && !globb && !wilda && !wildb && ca != cb)
return false;
if((globa && ap + 1 >= a.size()) || (globb && bp + 1 >= b.size()))
break;
if(globa && cb == tolower(a.at(ap + 1)))
ap += 2;
if(globb && ca == tolower(b.at(bp + 1)))
bp += 2;
if(globa && globb)
++ap, ++bp;
if(!globa)
++ap;
if(!globb)
++bp;
}
if(ap < a.size() && !b.empty() && b.back() == '*')
return true;
if(bp < b.size() && !a.empty() && a.back() == '*')
return true;
return std::equal(a.begin() + ap, a.end(), b.begin() + bp, b.end());
}
//
// gmatch
//
bool
ircd::gmatch::operator()(const string_view &a)
const
{
//TODO: optimize.
const gequals gequals(expr, a);
return bool(gequals);
}