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:
parent
680734c47b
commit
8aa67ccb48
2 changed files with 117 additions and 0 deletions
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue