utils/mu-regex: add move constructor

This commit is contained in:
Dirk-Jan C. Binnema 2023-07-11 00:30:23 +03:00
parent f3bfdf5add
commit 6f69f5d482
2 changed files with 84 additions and 29 deletions

View File

@ -39,6 +39,24 @@ test_regex_match()
g_assert_false(rx->matches("axxxxxbqqc")); g_assert_false(rx->matches("axxxxxbqqc"));
} }
static void
test_regex_match2()
{
Regex rx;
{
std::string foo = "h.llo";
rx = unwrap(Regex::make(foo.c_str()));
}
std::string hei = "hei";
g_assert_true(rx.matches("hallo"));
g_assert_false(rx.matches(hei));
}
static void static void
test_regex_replace() test_regex_replace()
{ {
@ -54,6 +72,7 @@ try {
mu_test_init(&argc, &argv); mu_test_init(&argc, &argv);
g_test_add_func("/regex/match", test_regex_match); g_test_add_func("/regex/match", test_regex_match);
g_test_add_func("/regex/match2", test_regex_match2);
g_test_add_func("/regex/replace", test_regex_replace); g_test_add_func("/regex/replace", test_regex_replace);
return g_test_run(); return g_test_run();

View File

@ -20,7 +20,9 @@
#define MU_REGEX_HH__ #define MU_REGEX_HH__
#include <glib.h> #include <glib.h>
#
#include <utils/mu-result.hh> #include <utils/mu-result.hh>
#include <utils/mu-utils.hh>
namespace Mu { namespace Mu {
/** /**
@ -50,19 +52,33 @@ struct Regex {
*/ */
static Result<Regex> make(const std::string& ptrn, static Result<Regex> make(const std::string& ptrn,
GRegexCompileFlags cflags = G_REGEX_DEFAULT, GRegexCompileFlags cflags = G_REGEX_DEFAULT,
GRegexMatchFlags mflags = G_REGEX_MATCH_DEFAULT) noexcept try { GRegexMatchFlags mflags = G_REGEX_MATCH_DEFAULT)
noexcept try {
return Regex(ptrn.c_str(), cflags, mflags); return Regex(ptrn.c_str(), cflags, mflags);
} catch (const Error& err) { } catch (const Error& err) {
return Err(err); return Err(err);
} }
/**
* Copy CTOR
*
* @param other some other Regex
*/
Regex(const Regex& other) noexcept: rx_{} { *this = other; }
/**
* Move CTOR
*
* @param other some other Regex
*/
Regex(Regex&& other) noexcept: rx_{} { *this = std::move(other); }
/** /**
* DTOR * DTOR
*/ */
~Regex() { ~Regex() noexcept { g_clear_pointer(&rx_, g_regex_unref); }
if (rx_)
g_regex_unref(rx_);
}
/** /**
* Cast to the the underlying GRegex* * Cast to the the underlying GRegex*
@ -78,15 +94,6 @@ struct Regex {
*/ */
operator bool() const noexcept { return !!rx_; } operator bool() const noexcept { return !!rx_; }
// No need for a move CTOR, copying is cheap (GRegex is ref-counted)
/**
* Copy CTOR
*
* @param other some other Regex
*/
Regex(const Regex& other) noexcept { *this = other; }
/** /**
* operator= * operator=
* *
@ -96,10 +103,25 @@ struct Regex {
*/ */
Regex& operator=(const Regex& other) noexcept { Regex& operator=(const Regex& other) noexcept {
if (this != &other) { if (this != &other) {
auto oldrx = rx_; g_clear_pointer(&rx_, g_regex_unref);
rx_ = other.rx_ ? g_regex_ref(other.rx_): nullptr; if (other.rx_)
if (oldrx) rx_ = g_regex_ref(other.rx_);
g_regex_unref(oldrx); }
return *this;
}
/**
* operator=
*
* @param other move some other object to this one
*
* @return *this
*/
Regex& operator=(Regex&& other) noexcept {
if (this != &other) {
g_clear_pointer(&rx_, g_regex_unref);
rx_ = other.rx_;
other.rx_ = nullptr;
} }
return *this; return *this;
} }
@ -108,14 +130,19 @@ struct Regex {
* Does this regexp match the given string? An unset Regex matches * Does this regexp match the given string? An unset Regex matches
* nothing. * nothing.
* *
* @param str * @param str string to test
* @param mflags * @param mflags match flags
* *
* @return true or false * @return true or false
*/ */
bool matches(const std::string& str, bool matches(const std::string& str,
GRegexMatchFlags mflags=G_REGEX_MATCH_DEFAULT) const noexcept { GRegexMatchFlags mflags=G_REGEX_MATCH_DEFAULT) const noexcept {
return rx_ ? g_regex_match(rx_, str.c_str(), mflags, {}) : false; if (!rx_)
return false;
else
return g_regex_match(rx_, str.c_str(), mflags, nullptr);
// strangely, valgrind reports some memory error related to
// the str.c_str(). It *seems* like a false alarm.
} }
/** /**
@ -132,22 +159,31 @@ struct Regex {
repl.c_str(), G_REGEX_MATCH_DEFAULT, {})}; repl.c_str(), G_REGEX_MATCH_DEFAULT, {})};
if (!s) if (!s)
throw Err(Error::Code::InvalidArgument, "error in Regex::replace"); throw Err(Error::Code::InvalidArgument, "error in Regex::replace");
std::string r{s}; return to_string_gchar(std::move(s));
g_free(s);
return r;
} }
const GRegex* g_regex() const { return rx_; }
private: private:
Regex(const char *ptrn, GRegexCompileFlags cflags, GRegexMatchFlags mflags) { Regex(const char *ptrn, GRegexCompileFlags cflags, GRegexMatchFlags mflags) {
GError *err{}; GError *err{};
rx_ = g_regex_new(ptrn, cflags, mflags, &err); if (rx_ = g_regex_new(ptrn, cflags, mflags, &err); !rx_)
if (!rx_) throw Err(Error::Code::InvalidArgument, &err,
throw Err(Error::Code::InvalidArgument, "invalid regexp: '{}'", ptrn);
"invalid regexp: '%s'", ptrn);
} }
GRegex *rx_{};
GRegex *rx_;
}; };
static inline std::string format_as(const Regex& rx) {
if (auto&& grx{rx.g_regex()}; !grx)
return "//";
else
return mu_format("/{}/", g_regex_get_pattern(grx));
}
} // namespace Mu } // namespace Mu