0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-25 08:12:37 +01:00

ircd: Split out overgrown components from stringops.h

This commit is contained in:
Jason Volk 2019-07-11 13:46:32 -07:00
parent d53744b3f8
commit de94e95422
8 changed files with 383 additions and 325 deletions

127
include/ircd/cmp.h Normal file
View file

@ -0,0 +1,127 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#pragma once
#define HAVE_IRCD_CMP_H
// Simple case insensitive comparison convenience utils
namespace ircd
{
struct iless;
struct igreater;
struct iequals;
}
/// Case insensitive string comparison deciding if two strings are equal
struct ircd::iequals
{
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>
iequals(A&& a, B&& b)
:s{operator()(std::forward<A>(a), std::forward<B>(b))}
{}
iequals() = default;
};
inline bool
ircd::iequals::operator()(const string_view &a,
const string_view &b)
const
{
return std::equal(begin(a), end(a), begin(b), end(b), []
(const char &a, const char &b)
{
return tolower(a) == tolower(b);
});
}
/// Case insensitive string comparison deciding which string compares 'less'
/// than the other.
struct ircd::iless
{
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>
iless(A&& a, B&& b)
:s{operator()(std::forward<A>(a), std::forward<B>(b))}
{}
iless() = default;
};
inline bool
ircd::iless::operator()(const string_view &a,
const string_view &b)
const
{
return std::lexicographical_compare(begin(a), end(a), begin(b), end(b), []
(const char &a, const char &b)
{
return tolower(a) < tolower(b);
});
}
/// Case insensitive string comparison deciding which string compares 'greater'
/// than the other.
struct ircd::igreater
{
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>
igreater(A&& a, B&& b)
:s{operator()(std::forward<A>(a), std::forward<B>(b))}
{}
igreater() = default;
};
inline bool
ircd::igreater::operator()(const string_view &a,
const string_view &b)
const
{
return std::lexicographical_compare(begin(a), end(a), begin(b), end(b), []
(const char &a, const char &b)
{
return tolower(a) > tolower(b);
});
}

74
include/ircd/globular.h Normal file
View file

@ -0,0 +1,74 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#pragma once
#define HAVE_IRCD_GLOBULAR_H
namespace ircd
{
// Globular ('*' and '?') expression utils.
struct globular_match;
struct globular_equals;
}
/// Globular equals. This allows either side of the comparison to include '*'
/// and '?' characters and equality of the string expressions will be
/// determined.
struct ircd::globular_equals
{
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>
globular_equals(A&& a, B&& b)
:s{operator()(std::forward<A>(a), std::forward<B>(b))}
{}
globular_equals() = default;
};
/// Globular match. Similar to globular_equals 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 globular_equals.
struct ircd::globular_match
{
string_view expr;
bool s;
operator const bool &() const
{
return s;
}
bool operator()(const string_view &a) const;
globular_match(const string_view &expr)
:expr{expr}
{}
template<class A>
globular_match(const string_view &expr, A&& a)
:expr{expr}
,s{operator()(std::forward<A>(a))}
{}
globular_match() = default;
};

View file

@ -36,6 +36,9 @@
#include "lex_cast.h"
#include "base.h"
#include "stringops.h"
#include "strl.h"
#include "cmp.h"
#include "globular.h"
#include "tokens.h"
#include "iov.h"
#include "grammar.h"

View file

@ -16,19 +16,6 @@
//
namespace ircd
{
// Simple case insensitive comparison convenience utils
struct iless;
struct igreater;
struct iequals;
// Globular ('*' and '?') expression utils.
struct globular_match;
struct globular_equals;
// Vintage
struct strlcpy;
struct strlcat;
// wrapper to find(T) != npos
template<class T> bool has(const string_view &, const T &);
inline bool ihas(const string_view &s, const string_view &t);
@ -108,259 +95,6 @@ namespace ircd
string_view trunc(const string_view &, const size_t &max);
}
/// This is a function. It works the same as the standard strlcpy() but it has
/// some useful modernizations and may be informally referred to as strlcpy++.
///
/// - It optionally works with string_view inputs and ircd::buffer outputs.
/// This allows for implicit size parameters and increases its safety while
/// simplifying its usage (no more sizeof(buf) where buf coderots into char*).
///
/// - Its objectification allows for a configurable return type. The old
/// strlcpy() returned a size integer type. When using string_view's and
/// buffers this would generally lead to the pattern { dst, strlcpy(dst, src) }
/// and this is no longer necessary.
///
struct ircd::strlcpy
{
mutable_buffer ret;
public:
operator string_view() const
{
return ret;
}
operator size_t() const
{
return size(ret);
}
strlcpy(char *const &dst, const string_view &src, const size_t &max)
:ret{[&]() -> mutable_buffer
{
if(!max)
return {};
const auto len{std::min(src.size(), max - 1)};
memcpy(dst, src.data(), len);
dst[len] = '\0';
return { dst, len };
}()}
{}
#ifndef HAVE_STRLCPY
strlcpy(char *const &dst, const char *const &src, const size_t &max)
:strlcpy{dst, string_view{src, strnlen(src, max)}, max}
{}
#endif
strlcpy(const mutable_buffer &dst, const string_view &src)
:strlcpy{data(dst), src, size(dst)}
{}
};
/// This is a function. It works the same as the standard strlcat() but it has
/// some useful modernizations and may be informally referred to as strlcat++.
/// see: ircd::strlcpy().
///
struct ircd::strlcat
{
mutable_buffer ret;
public:
operator string_view() const
{
return ret;
}
operator size_t() const
{
return size(ret);
}
strlcat(char *const &dst, const string_view &src, const size_t &max)
:ret{[&]() -> mutable_buffer
{
const auto pos{strnlen(dst, max)};
const auto remain{max - pos};
strlcpy(dst + pos, src, remain);
return { dst, pos + src.size() };
}()}
{}
#ifndef HAVE_STRLCAT
strlcat(char *const &dst, const char *const &src, const size_t &max)
:strlcat{dst, string_view{src, ::strnlen(src, max)}, max}
{}
#endif
strlcat(const mutable_buffer &dst, const string_view &src)
:strlcat{data(dst), src, size(dst)}
{}
};
/// Case insensitive string comparison deciding if two strings are equal
struct ircd::iequals
{
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>
iequals(A&& a, B&& b)
:s{operator()(std::forward<A>(a), std::forward<B>(b))}
{}
iequals() = default;
};
inline bool
ircd::iequals::operator()(const string_view &a,
const string_view &b)
const
{
return std::equal(begin(a), end(a), begin(b), end(b), []
(const char &a, const char &b)
{
return tolower(a) == tolower(b);
});
}
/// Case insensitive string comparison deciding which string compares 'less'
/// than the other.
struct ircd::iless
{
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>
iless(A&& a, B&& b)
:s{operator()(std::forward<A>(a), std::forward<B>(b))}
{}
iless() = default;
};
inline bool
ircd::iless::operator()(const string_view &a,
const string_view &b)
const
{
return std::lexicographical_compare(begin(a), end(a), begin(b), end(b), []
(const char &a, const char &b)
{
return tolower(a) < tolower(b);
});
}
/// Case insensitive string comparison deciding which string compares 'greater'
/// than the other.
struct ircd::igreater
{
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>
igreater(A&& a, B&& b)
:s{operator()(std::forward<A>(a), std::forward<B>(b))}
{}
igreater() = default;
};
inline bool
ircd::igreater::operator()(const string_view &a,
const string_view &b)
const
{
return std::lexicographical_compare(begin(a), end(a), begin(b), end(b), []
(const char &a, const char &b)
{
return tolower(a) > tolower(b);
});
}
/// Globular equals. This allows either side of the comparison to include '*'
/// and '?' characters and equality of the string expressions will be
/// determined.
struct ircd::globular_equals
{
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>
globular_equals(A&& a, B&& b)
:s{operator()(std::forward<A>(a), std::forward<B>(b))}
{}
globular_equals() = default;
};
/// Globular match. Similar to globular_equals 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 globular_equals.
struct ircd::globular_match
{
string_view expr;
bool s;
operator const bool &() const
{
return s;
}
bool operator()(const string_view &a) const;
globular_match(const string_view &expr)
:expr{expr}
{}
template<class A>
globular_match(const string_view &expr, A&& a)
:expr{expr}
,s{operator()(std::forward<A>(a))}
{}
globular_match() = default;
};
inline ircd::string_view
ircd::trunc(const string_view &s,
const size_t &max)

110
include/ircd/strl.h Normal file
View file

@ -0,0 +1,110 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#pragma once
#define HAVE_IRCD_STRL_H
// Vintage
namespace ircd
{
struct strlcpy;
struct strlcat;
}
/// This is a function. It works the same as the standard strlcpy() but it has
/// some useful modernizations and may be informally referred to as strlcpy++.
///
/// - It optionally works with string_view inputs and ircd::buffer outputs.
/// This allows for implicit size parameters and increases its safety while
/// simplifying its usage (no more sizeof(buf) where buf coderots into char*).
///
/// - Its objectification allows for a configurable return type. The old
/// strlcpy() returned a size integer type. When using string_view's and
/// buffers this would generally lead to the pattern { dst, strlcpy(dst, src) }
/// and this is no longer necessary.
///
struct ircd::strlcpy
{
mutable_buffer ret;
public:
operator string_view() const
{
return ret;
}
operator size_t() const
{
return size(ret);
}
strlcpy(char *const &dst, const string_view &src, const size_t &max)
:ret{[&]() -> mutable_buffer
{
if(!max)
return {};
const auto len{std::min(src.size(), max - 1)};
memcpy(dst, src.data(), len);
dst[len] = '\0';
return { dst, len };
}()}
{}
#ifndef HAVE_STRLCPY
strlcpy(char *const &dst, const char *const &src, const size_t &max)
:strlcpy{dst, string_view{src, strnlen(src, max)}, max}
{}
#endif
strlcpy(const mutable_buffer &dst, const string_view &src)
:strlcpy{data(dst), src, size(dst)}
{}
};
/// This is a function. It works the same as the standard strlcat() but it has
/// some useful modernizations and may be informally referred to as strlcat++.
/// see: ircd::strlcpy().
///
struct ircd::strlcat
{
mutable_buffer ret;
public:
operator string_view() const
{
return ret;
}
operator size_t() const
{
return size(ret);
}
strlcat(char *const &dst, const string_view &src, const size_t &max)
:ret{[&]() -> mutable_buffer
{
const auto pos{strnlen(dst, max)};
const auto remain{max - pos};
strlcpy(dst + pos, src, remain);
return { dst, pos + src.size() };
}()}
{}
#ifndef HAVE_STRLCAT
strlcat(char *const &dst, const char *const &src, const size_t &max)
:strlcat{dst, string_view{src, ::strnlen(src, max)}, max}
{}
#endif
strlcat(const mutable_buffer &dst, const string_view &src)
:strlcat{data(dst), src, size(dst)}
{}
};

View file

@ -125,6 +125,7 @@ libircd_la_SOURCES += demangle.cc
libircd_la_SOURCES += locale.cc
libircd_la_SOURCES += lex_cast.cc
libircd_la_SOURCES += stringops.cc
libircd_la_SOURCES += globular.cc
libircd_la_SOURCES += tokens.cc
libircd_la_SOURCES += parse.cc
libircd_la_SOURCES += rand.cc

68
ircd/globular.cc Normal file
View file

@ -0,0 +1,68 @@
// Matrix Construct
//
// Copyright (C) Matrix Construct Developers, Authors & Contributors
// Copyright (C) 2016-2019 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
//
// globular_equals
//
bool
ircd::globular_equals::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 iequals(a.substr(ap), b.substr(bp));
}
//
// globular_match
//
bool
ircd::globular_match::operator()(const string_view &a)
const
{
//TODO: optimize.
const globular_equals globular_equals(expr, a);
return bool(globular_equals);
}

View file

@ -42,62 +42,3 @@ ircd::replace(const string_view &s,
return std::distance(begin(buf), p);
});
}
//
// globular_equals
//
bool
ircd::globular_equals::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 iequals(a.substr(ap), b.substr(bp));
}
//
// globular_match
//
bool
ircd::globular_match::operator()(const string_view &a)
const
{
//TODO: optimize.
const globular_equals globular_equals(expr, a);
return bool(globular_equals);
}