From 6deb2545b5da048991b53c27b03a60dd206f477a Mon Sep 17 00:00:00 2001 From: moemod <824395314@qq.com> Date: Wed, 19 Feb 2020 01:15:33 +0800 Subject: [PATCH 1/3] template dolores::matchers --- include/dolores/handler.hpp | 49 +++-- include/dolores/matcher.hpp | 373 +++++++++------------------------ include/dolores/string.hpp | 19 +- include/dolores/traits.hpp | 14 +- tests/test_dolores_matcher.cpp | 11 +- 5 files changed, 148 insertions(+), 318 deletions(-) diff --git a/include/dolores/handler.hpp b/include/dolores/handler.hpp index 0ef167f..7a7d108 100644 --- a/include/dolores/handler.hpp +++ b/include/dolores/handler.hpp @@ -13,27 +13,15 @@ #include "traits.hpp" namespace dolores { - template >> + template class Handler { + static_assert(is_derived_from_user_event_v); public: - explicit Handler(std::function ¤t)> func, std::shared_ptr matcher = nullptr) - : _func(std::move(func)), _matcher(std::move(matcher)) { - } - - bool match(const E &event, Session &session) const { - if (!_matcher) return true; - return _matcher->match(event, session); - } - - void run(Current ¤t) const { - if (!_func) return; - _func(current); - } - - private: - std::shared_ptr _matcher; - std::function ¤t)> _func; + virtual ~Handler() = 0; + virtual bool match(const E &event, Session &session) const = 0; + virtual void run(Current ¤t) = 0; }; + inline Handler::~Handler() = default; struct _HandlerVecWrapper { template >> @@ -80,6 +68,27 @@ namespace dolores { } } } + + template + class HandlerImplementation : public Handler { + static_assert(is_derived_from_user_event_v); + public: + explicit HandlerImplementation(Func func, AllMatcher matcher) + : _func(std::move(func)), _matcher(std::move(matcher)) { + } + + bool match(const E &event, Session &session) const override { + return _matcher(event, session); + } + + void run(Current ¤t) const override { + _func(current); + } + + private: + RunFunc _func; + AllMatcher _matcher; + }; } // namespace dolores #define _DOLORES_UNIQUE_NAME_2(Name, Number) Name##Number @@ -88,8 +97,8 @@ namespace dolores { #define _DOLORES_MAKE_HANDLER_2(EventType, FuncName, ...) \ static void FuncName(dolores::Current &); \ - static const auto FuncName##_res = dolores::add_handler(std::make_shared>( \ - FuncName, std::make_shared(__VA_ARGS__))); \ + static const auto FuncName##_res = dolores::add_handler(std::make_shared>( \ + FuncName, dolores::matchers::all(__VA_ARGS__))); \ static void FuncName(dolores::Current ¤t) #define _DOLORES_MAKE_HANDLER(EventType, FuncName, ...) _DOLORES_MAKE_HANDLER_2(EventType, FuncName, __VA_ARGS__) diff --git a/include/dolores/matcher.hpp b/include/dolores/matcher.hpp index c723b64..fd0dbcb 100644 --- a/include/dolores/matcher.hpp +++ b/include/dolores/matcher.hpp @@ -17,308 +17,95 @@ #include "watashi.hpp" namespace dolores { - class MatcherBase { - public: - virtual bool match(const cq::MessageEvent &event, Session &session) const { - return match(static_cast(event), session); - } + class MatcherBase {}; - virtual bool match(const cq::NoticeEvent &event, Session &session) const { - return match(static_cast(event), session); - } + class MessageMatcher : public MatcherBase {}; - virtual bool match(const cq::RequestEvent &event, Session &session) const { - return match(static_cast(event), session); - } - - virtual bool match(const cq::UserEvent &event, Session &session) const { - return false; - } - }; - - class MessageMatcher : virtual public MatcherBase { - public: - virtual bool match(const cq::Target &target, const std::string_view &message, Session &session) const { - return false; + namespace matchers { + inline namespace { + // another overload is in traits.hpp, for ADL + template std::true_type is_in_matchers_namespace(Fn &&); } - bool match(const cq::MessageEvent &event, Session &session) const final { - return match(event.target, event.message, session); + template + constexpr auto operator!(T &&matcher) { + return [matcher](auto&&...args){ return !matcher(std::forward(args)...); }; } - }; - - namespace matchers { - class _NotMatcher : public MatcherBase { - public: - template >> - explicit _NotMatcher(T &&matcher) : _matcher(std::make_shared>(std::forward(matcher))) { - } - - bool match(const cq::MessageEvent &event, Session &session) const override { - return _match(event, session); - } - - bool match(const cq::NoticeEvent &event, Session &session) const override { - return _match(event, session); - } - - bool match(const cq::RequestEvent &event, Session &session) const override { - return _match(event, session); - } - - bool match(const cq::UserEvent &event, Session &session) const override { - return _match(event, session); - } - - protected: - std::shared_ptr _matcher; - - template - bool _match(const E &event, Session &session) const { - return !_matcher->match(event, session); - } - }; - - class _NotMessageMatcher : public MessageMatcher { - public: - template >> - explicit _NotMessageMatcher(T &&matcher) - : _matcher(std::make_shared>(std::forward(matcher))) { - } - - bool match(const cq::Target &target, const std::string_view &message, Session &session) const override { - return !_matcher->match(target, message, session); - } - - protected: - std::shared_ptr _matcher; - }; - - class _AndMatcher : public MatcherBase { - public: - template >> - _AndMatcher(TL &&lhs, TR &&rhs) - : _lhs(std::make_shared>(std::forward(lhs))), - _rhs(std::make_shared>(std::forward(rhs))) { - } - - bool match(const cq::MessageEvent &event, Session &session) const override { - return _match(event, session); - } - - bool match(const cq::NoticeEvent &event, Session &session) const override { - return _match(event, session); - } - - bool match(const cq::RequestEvent &event, Session &session) const override { - return _match(event, session); - } - - bool match(const cq::UserEvent &event, Session &session) const override { - return _match(event, session); - } - - protected: - std::shared_ptr _lhs; - std::shared_ptr _rhs; - - template - bool _match(const E &event, Session &session) const { - return _lhs->match(event, session) && _rhs->match(event, session); - } - }; - - class _AndMessageMatcher : public MessageMatcher { - public: - template >> - _AndMessageMatcher(TL &&lhs, TR &&rhs) - : _lhs(std::make_shared>(std::forward(lhs))), - _rhs(std::make_shared>(std::forward(rhs))) { - } - - bool match(const cq::Target &target, const std::string_view &message, Session &session) const override { - return _lhs->match(target, message, session) && _rhs->match(target, message, session); - } - - protected: - std::shared_ptr _lhs; - std::shared_ptr _rhs; - }; - - class _OrMatcher : public MatcherBase { - public: - template >> - _OrMatcher(TL &&lhs, TR &&rhs) - : _lhs(std::make_shared>(std::forward(lhs))), - _rhs(std::make_shared>(std::forward(rhs))) { - } - - bool match(const cq::MessageEvent &event, Session &session) const override { - return _match(event, session); - } - - bool match(const cq::NoticeEvent &event, Session &session) const override { - return _match(event, session); - } - - bool match(const cq::RequestEvent &event, Session &session) const override { - return _match(event, session); - } - - bool match(const cq::UserEvent &event, Session &session) const override { - return _match(event, session); - } - - protected: - std::shared_ptr _lhs; - std::shared_ptr _rhs; - - template - bool _match(const E &event, Session &session) const { - return _lhs->match(event, session) || _rhs->match(event, session); - } - }; - - class _OrMessageMatcher : public MessageMatcher { - public: - template >> - _OrMessageMatcher(TL &&lhs, TR &&rhs) - : _lhs(std::make_shared>(std::forward(lhs))), - _rhs(std::make_shared>(std::forward(rhs))) { - } - - bool match(const cq::Target &target, const std::string_view &message, Session &session) const override { - return _lhs->match(target, message, session) || _rhs->match(target, message, session); - } - - protected: - std::shared_ptr _lhs; - std::shared_ptr _rhs; - }; - template >> - inline auto operator!(T &&matcher) { - if constexpr (is_message_matcher_v) { - return _NotMessageMatcher(std::forward(matcher)); - } else { - return _NotMatcher(std::forward(matcher)); - } + template > && is_matcher_v>>> + constexpr auto operator&&(TL &&lhs, TR &&rhs) { + return [lhs, rhs](auto&&...args){ return lhs(args...) && rhs(args...); }; } - template >> - inline auto operator&&(TL &&lhs, TR &&rhs) { - if constexpr (is_message_matcher_v && is_message_matcher_v) { - return _AndMessageMatcher(std::forward(lhs), std::forward(rhs)); - } else { - return _AndMatcher(std::forward(lhs), std::forward(rhs)); - } + template > && is_matcher_v>>> + constexpr auto operator||(TL &&lhs, TR &&rhs) { + return [lhs, rhs](auto&&...args){ return lhs(args...) || rhs(args...); }; } - template >> - inline auto operator||(TL &&lhs, TR &&rhs) { - if constexpr (is_message_matcher_v && is_message_matcher_v) { - return _OrMessageMatcher(std::forward(lhs), std::forward(rhs)); - } else { - return _OrMatcher(std::forward(lhs), std::forward(rhs)); - } + template + constexpr auto all(Matchers &&...matchers) { + return [matchers...](auto&&...args){ return (matchers(args...) && ...); }; } - class all : public MatcherBase { - public: - template - explicit all(Matchers &&... matchers) - : _matchers({std::make_shared>(std::forward(matchers))...}) { - } - - bool match(const cq::MessageEvent &event, Session &session) const override { - return _match(event, session); - } - - bool match(const cq::NoticeEvent &event, Session &session) const override { - return _match(event, session); - } - - bool match(const cq::RequestEvent &event, Session &session) const override { - return _match(event, session); - } - - bool match(const cq::UserEvent &event, Session &session) const override { - return _match(event, session); - } - - protected: - std::vector> _matchers; - - template - bool _match(const E &event, Session &session) const { - return std::all_of(_matchers.cbegin(), _matchers.cend(), [&](const auto &matcher) { - return matcher->match(event, session); - }); - } - }; - template - struct _type { - class matcher_t : public MatcherBase { - public: - bool match(const cq::UserEvent &event, Session &session) const override { - return typeid(event) == typeid(E); - } - }; - - static constexpr matcher_t matcher{}; - }; + constexpr auto type = [](const auto &event, Session &session){ return typeid(event) == typeid(E); }; - template - constexpr auto type = _type::matcher; - - class unblocked : public MatcherBase { - public: - bool match(const cq::UserEvent &event, Session &session) const override { - return !event.blocked(); - } - }; + constexpr auto unblocked() { + return [](const cq::UserEvent &event, Session &session){ return !event.blocked(); }; + } - class startswith : public MessageMatcher { + class startswith { public: explicit startswith(std::string prefix) : _prefix(std::move(prefix)) { } - bool match(const cq::Target &target, const std::string_view &message, Session &session) const override { + bool operator()(const cq::Target &target, const std::string_view &message, Session &session) const { return string::startswith(message, _prefix); } + bool operator()(const cq::MessageEvent &event, Session &session) const { + return (*this)(event.target, event.message, session); + } + protected: std::string _prefix; }; - class endswith : public MessageMatcher { + class endswith { public: explicit endswith(std::string suffix) : _suffix(std::move(suffix)) { } - bool match(const cq::Target &target, const std::string_view &message, Session &session) const override { + bool operator()(const cq::Target &target, const std::string_view &message, Session &session) const { return string::endswith(message, _suffix); } + bool operator()(const cq::MessageEvent &event, Session &session) const { + return (*this)(event.target, event.message, session); + } + protected: std::string _suffix; }; - class contains : public MessageMatcher { + class contains { public: explicit contains(std::string sub) : _sub(std::move(sub)) { } - bool match(const cq::Target &target, const std::string_view &message, Session &session) const override { + bool operator()(const cq::Target &target, const std::string_view &message, Session &session) const { return string::contains(message, _sub); } + bool operator()(const cq::MessageEvent &event, Session &session) const { + return (*this)(event.target, event.message, session); + } + protected: std::string _sub; }; - class command : public MessageMatcher { + class command { public: static constexpr auto STARTER = "_cond__command__starter"; static constexpr auto NAME = "_cond__command__name"; @@ -332,9 +119,8 @@ namespace dolores { : _names(names), _starters(std::move(starters)) { } - bool match(const cq::Target &target, const std::string_view &message, Session &session) const override { + bool operator()(const cq::Target &target, const std::string_view &message, Session &session) const { static const std::vector default_starters = {"/", "!", ".", "!", "。"}; - const auto message_v = string::string_view_from( std::find_if_not(message.cbegin(), message.cend(), cq::utils::isspace_s), message.cend()); @@ -369,22 +155,24 @@ namespace dolores { return res; } + bool operator()(const cq::MessageEvent &event, Session &session) const { + return (*this)(event.target, event.message, session); + } + protected: std::vector _names; std::vector _starters; }; - class to_me : public MessageMatcher { + template + class to_me { public: - to_me() = default; - - template >> - explicit to_me(T &&matcher) : _sub_matcher(std::make_shared>(std::forward(matcher))) { + explicit to_me(T &&matcher) : _sub_matcher(matcher) { } - bool match(const cq::Target &target, const std::string_view &message, Session &session) const override { + bool operator()(const cq::Target &target, const std::string_view &message, Session &session) const { if (target.is_private()) { - return _sub_matcher ? _sub_matcher->match(target, message, session) : true; + return _sub_matcher(target, message, session); } using cq::message::MessageSegment; @@ -392,8 +180,6 @@ namespace dolores { const auto at_me_off = message.find(at_me_seg); if (at_me_off == std::string_view::npos) { return false; - } else if (!_sub_matcher) { - return true; } // assert: _sub_matcher is not null @@ -404,7 +190,7 @@ namespace dolores { const auto before_at_v = std::string_view(message.data(), at_me_off); const auto after_at_v = - string::string_view_from(message.cbegin() + at_me_off + at_me_seg.length(), message.cend()); + string::string_view_from(message.cbegin() + at_me_off + at_me_seg.length(), message.cend()); std::string_view cut_message_v; if (is_full_of_spaces(before_at_v)) { // @me is at the beginning of message @@ -416,14 +202,45 @@ namespace dolores { // @me is in the middle of message cut_message_v = message; } - return _sub_matcher->match(target, cut_message_v, session); + return _sub_matcher(target, cut_message_v, session); + }; + + bool operator()(const cq::MessageEvent &event, Session &session) const { + return (*this)(event.target, event.message, session); } private: - std::shared_ptr _sub_matcher; + T _sub_matcher; + }; + + template<> + class to_me { + public: + to_me() = default; + + bool operator()(const cq::Target &target, const std::string_view &message, Session &session) const { + if (target.is_private()) { + return true; + } + + using cq::message::MessageSegment; + const auto at_me_seg = cq::to_string(MessageSegment::at(watashi::user_id())); + const auto at_me_off = message.find(at_me_seg); + if (at_me_off == std::string_view::npos) { + return false; + } + + return true; + }; + + bool operator()(const cq::MessageEvent &event, Session &session) const { + return (*this)(event.target, event.message, session); + } }; + to_me() -> to_me; + template to_me(T) -> to_me; - class user : public MatcherBase { + class user { public: user() = default; @@ -436,7 +253,7 @@ namespace dolores { return u; } - bool match(const cq::UserEvent &event, Session &session) const override { + bool operator()(const cq::UserEvent &event, Session &session) const { if (!_include_users.empty()) { return std::find(_include_users.cbegin(), _include_users.cend(), event.user_id) != _include_users.cend(); @@ -463,13 +280,13 @@ namespace dolores { return d; } - bool match(const cq::UserEvent &event, Session &session) const override { + bool operator()(const cq::UserEvent &event, Session &session) const { if (!event.target.is_private()) return false; - return user::match(event, session); + return user::operator()(event, session); } }; - class group : public MatcherBase { + class group { public: group() = default; @@ -482,7 +299,7 @@ namespace dolores { return g; } - bool match(const cq::UserEvent &event, Session &session) const override { + bool operator()(const cq::UserEvent &event, Session &session) const { if (!event.target.is_group()) return false; const auto group_id = event.target.group_id.value_or(0); @@ -502,19 +319,19 @@ namespace dolores { std::vector _exclude_groups; }; - class discuss : public MatcherBase { + class discuss { public: - bool match(const cq::UserEvent &event, Session &session) const override { + bool operator()(const cq::UserEvent &event, Session &session) const { return event.target.is_discuss(); } }; - class group_roles : public MatcherBase { + class group_roles { public: explicit group_roles(std::vector roles) : _roles(std::move(roles)) { } - bool match(const cq::UserEvent &event, Session &session) const override { + bool operator()(const cq::UserEvent &event, Session &session) const { if (!event.target.is_group()) return true; // ignore non-group event const auto group_id = event.target.group_id.value_or(0); diff --git a/include/dolores/string.hpp b/include/dolores/string.hpp index e6ec22c..43b9dd7 100644 --- a/include/dolores/string.hpp +++ b/include/dolores/string.hpp @@ -1,25 +1,28 @@ #pragma once #include +#include namespace dolores::string { - inline bool startswith(const std::string_view &sv, const std::string_view &prefix) { + constexpr bool startswith(std::string_view sv, std::string_view prefix) { return sv.substr(0, prefix.length()) == prefix; } - inline bool endswith(const std::string_view &sv, const std::string_view &suffix) { + constexpr bool endswith(std::string_view sv, std::string_view suffix) { if (sv.length() < suffix.length()) return false; return sv.substr(sv.length() - suffix.length()) == suffix; } - inline bool contains(const std::string_view &sv, const std::string_view &sub) { + constexpr bool contains(std::string_view sv, std::string_view sub) { return sv.find(sub) != std::string_view ::npos; } - template - inline std::string_view string_view_from(It first, End last) { - const auto size = last - first; - if (size <= 0) return std::string_view(""); - return std::string_view(&*first, size); + constexpr std::string_view string_view_from(std::string_view::const_iterator first, std::string_view::const_iterator last) { + return std::string_view(&*first, std::distance(first, last)); } + + inline std::string_view string_view_from(std::string::const_iterator first, std::string::const_iterator last) { + return std::string_view(&*first, std::distance(first, last)); + } + } // namespace dolores::string diff --git a/include/dolores/traits.hpp b/include/dolores/traits.hpp index 1400f5a..abc5ed0 100644 --- a/include/dolores/traits.hpp +++ b/include/dolores/traits.hpp @@ -9,15 +9,9 @@ namespace dolores { static constexpr auto is_derived_from_user_event_v = std::is_base_of_v> && !std::is_same_v>; - struct MatcherBase; + std::false_type is_in_matchers_namespace(...); + // another overload is in matcher.hpp, for ADL - template - static constexpr auto is_matcher_v = - std::is_base_of_v>&& std::is_base_of_v>; - - struct MessageMatcher; - - template - static constexpr auto is_message_matcher_v = - std::is_base_of_v>&& std::is_base_of_v>; + template + static constexpr auto is_matcher_v = decltype(is_in_matchers_namespace(std::declval()))::value; } // namespace dolores diff --git a/tests/test_dolores_matcher.cpp b/tests/test_dolores_matcher.cpp index ea7ed57..c78a00f 100644 --- a/tests/test_dolores_matcher.cpp +++ b/tests/test_dolores_matcher.cpp @@ -10,9 +10,16 @@ std::pair construct_pm() { return {cq::PrivateMessageEvent(1, 1, "hello, world", 0, cq::PrivateMessageEvent::SubType::FRIEND), Session()}; } +template +struct MatcherWrapper +{ + template bool match(Args &&...args) const { return x(std::forward(args)...); } + T x; +}; + template -std::shared_ptr to_matcher(Cond &&c) { - return std::make_shared>(std::forward(c)); +auto to_matcher(Cond &&c) { + return std::make_shared>(MatcherWrapper{std::forward(c)}); } TEST_CASE("matchers::operator!", "[matcher]") { From dc77e9e36115a16c381439c46b190f8eeb8bff55 Mon Sep 17 00:00:00 2001 From: MoeMod <824395314@qq.com> Date: Wed, 19 Feb 2020 02:43:44 +0800 Subject: [PATCH 2/3] fix msvc compiling --- include/dolores/matcher.hpp | 44 ++++++++++++++++--------------------- include/dolores/traits.hpp | 30 ++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 26 deletions(-) diff --git a/include/dolores/matcher.hpp b/include/dolores/matcher.hpp index fd0dbcb..8bf80e4 100644 --- a/include/dolores/matcher.hpp +++ b/include/dolores/matcher.hpp @@ -17,41 +17,34 @@ #include "watashi.hpp" namespace dolores { - class MatcherBase {}; - - class MessageMatcher : public MatcherBase {}; - namespace matchers { - inline namespace { - // another overload is in traits.hpp, for ADL - template std::true_type is_in_matchers_namespace(Fn &&); - } - - template + template >>> constexpr auto operator!(T &&matcher) { - return [matcher](auto&&...args){ return !matcher(std::forward(args)...); }; + return [matcher](auto &&... args) { return !matcher(std::forward(args)...); }; } - template > && is_matcher_v>>> + template > && is_matcher_v>>> constexpr auto operator&&(TL &&lhs, TR &&rhs) { - return [lhs, rhs](auto&&...args){ return lhs(args...) && rhs(args...); }; + return [lhs, rhs](auto &&... args) { return lhs(args...) && rhs(args...); }; } - template > && is_matcher_v>>> + template > && is_matcher_v>>> constexpr auto operator||(TL &&lhs, TR &&rhs) { - return [lhs, rhs](auto&&...args){ return lhs(args...) || rhs(args...); }; + return [lhs, rhs](auto &&... args) { return lhs(args...) || rhs(args...); }; } - template - constexpr auto all(Matchers &&...matchers) { - return [matchers...](auto&&...args){ return (matchers(args...) && ...); }; + template + constexpr auto all(Matchers &&... matchers) { + return [=](auto &&... args) { return (matchers(args...) && ...); }; } template - constexpr auto type = [](const auto &event, Session &session){ return typeid(event) == typeid(E); }; + constexpr auto type = [](const auto &event, Session &session) { return typeid(event) == typeid(E); }; constexpr auto unblocked() { - return [](const cq::UserEvent &event, Session &session){ return !event.blocked(); }; + return [](const cq::UserEvent &event, Session &session) { return !event.blocked(); }; } class startswith { @@ -164,7 +157,7 @@ namespace dolores { std::vector _starters; }; - template + template class to_me { public: explicit to_me(T &&matcher) : _sub_matcher(matcher) { @@ -190,7 +183,7 @@ namespace dolores { const auto before_at_v = std::string_view(message.data(), at_me_off); const auto after_at_v = - string::string_view_from(message.cbegin() + at_me_off + at_me_seg.length(), message.cend()); + string::string_view_from(message.cbegin() + at_me_off + at_me_seg.length(), message.cend()); std::string_view cut_message_v; if (is_full_of_spaces(before_at_v)) { // @me is at the beginning of message @@ -213,7 +206,7 @@ namespace dolores { T _sub_matcher; }; - template<> + template <> class to_me { public: to_me() = default; @@ -237,8 +230,9 @@ namespace dolores { return (*this)(event.target, event.message, session); } }; - to_me() -> to_me; - template to_me(T) -> to_me; + to_me()->to_me; + template + to_me(T)->to_me; class user { public: diff --git a/include/dolores/traits.hpp b/include/dolores/traits.hpp index abc5ed0..4c9ee79 100644 --- a/include/dolores/traits.hpp +++ b/include/dolores/traits.hpp @@ -9,8 +9,36 @@ namespace dolores { static constexpr auto is_derived_from_user_event_v = std::is_base_of_v> && !std::is_same_v>; + namespace matchers { +#if __cpp_concepts + template + concept MatcherBase = requires(T matcher, const cq::MessageEvent &event, Session &session) { + { matcher(event, session) } + ->std::boolean; + }; + + template + concept MessageMatcher = MatcherBase &&requires(T matcher, const cq::Target &target, + std::string_view message, Session &session) { + { matcher(target, message, session) } + ->std::boolean; + }; +#endif + inline namespace { + template + auto is_in_matchers_namespace(T &&) +#if __cpp_concepts + requires MatcherBase +#else + -> std::enable_if_t, std::true_type> +#endif + { + return std::true_type(); + } + } // namespace + } + std::false_type is_in_matchers_namespace(...); - // another overload is in matcher.hpp, for ADL template static constexpr auto is_matcher_v = decltype(is_in_matchers_namespace(std::declval()))::value; From a7e9cd6294759be624abe2df200303210398fc69 Mon Sep 17 00:00:00 2001 From: moemod <824395314@qq.com> Date: Sun, 23 Feb 2020 14:45:46 +0800 Subject: [PATCH 3/3] bitset group_roles --- include/dolores/matcher.hpp | 42 ++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/include/dolores/matcher.hpp b/include/dolores/matcher.hpp index 8bf80e4..247ac6b 100644 --- a/include/dolores/matcher.hpp +++ b/include/dolores/matcher.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "session.hpp" #include "string.hpp" @@ -49,10 +50,10 @@ namespace dolores { class startswith { public: - explicit startswith(std::string prefix) : _prefix(std::move(prefix)) { + explicit constexpr startswith(std::string_view prefix) : _prefix(prefix) { } - bool operator()(const cq::Target &target, const std::string_view &message, Session &session) const { + constexpr bool operator()(const cq::Target &target, const std::string_view &message, Session &session) const { return string::startswith(message, _prefix); } @@ -61,15 +62,15 @@ namespace dolores { } protected: - std::string _prefix; + std::string_view _prefix; }; class endswith { public: - explicit endswith(std::string suffix) : _suffix(std::move(suffix)) { + explicit constexpr endswith(std::string_view suffix) : _suffix(suffix) { } - bool operator()(const cq::Target &target, const std::string_view &message, Session &session) const { + constexpr bool operator()(const cq::Target &target, const std::string_view &message, Session &session) const { return string::endswith(message, _suffix); } @@ -78,15 +79,15 @@ namespace dolores { } protected: - std::string _suffix; + std::string_view _suffix; }; class contains { public: - explicit contains(std::string sub) : _sub(std::move(sub)) { + explicit constexpr contains(std::string_view sub) : _sub(sub) { } - bool operator()(const cq::Target &target, const std::string_view &message, Session &session) const { + constexpr bool operator()(const cq::Target &target, const std::string_view &message, Session &session) const { return string::contains(message, _sub); } @@ -95,7 +96,7 @@ namespace dolores { } protected: - std::string _sub; + std::string_view _sub; }; class command { @@ -209,7 +210,7 @@ namespace dolores { template <> class to_me { public: - to_me() = default; + constexpr to_me() = default; bool operator()(const cq::Target &target, const std::string_view &message, Session &session) const { if (target.is_private()) { @@ -322,8 +323,15 @@ namespace dolores { class group_roles { public: - explicit group_roles(std::vector roles) : _roles(std::move(roles)) { - } + static constexpr std::size_t MAX_ROLES = 3; + + //template + //constexpr group_roles(std::initializer_list il, std::index_sequence) : _roles(((1ull << static_cast(*(il.begin() + I))) || ...)) {} + + //constexpr group_roles(std::initializer_list il) : group_roles(il, std::make_index_sequence()) {} + + template && ...)>> + constexpr group_roles(Args...args) : _roles(((1ull << static_cast(args)) || ...)) { } bool operator()(const cq::UserEvent &event, Session &session) const { if (!event.target.is_group()) return true; // ignore non-group event @@ -331,12 +339,12 @@ namespace dolores { const auto group_id = event.target.group_id.value_or(0); try { const auto mi = cq::get_group_member_info(group_id, event.user_id); - return std::find(_roles.cbegin(), _roles.cend(), mi.role) != _roles.cend(); + return _roles.test(static_cast(mi.role)); } catch (cq::ApiError &) { // try again with cache disabled try { const auto mi = cq::get_group_member_info(group_id, event.user_id, true); - return std::find(_roles.cbegin(), _roles.cend(), mi.role) != _roles.cend(); + return _roles.test(static_cast(mi.role)); } catch (cq::ApiError &) { return false; } @@ -344,18 +352,18 @@ namespace dolores { } protected: - std::vector _roles; + std::bitset _roles; }; class admin : public group_roles { public: - admin() : group_roles({cq::GroupRole::ADMIN, cq::GroupRole::OWNER}) { + constexpr admin() : group_roles({cq::GroupRole::ADMIN, cq::GroupRole::OWNER}) { } }; class owner : public group_roles { public: - owner() : group_roles({cq::GroupRole::OWNER}) { + constexpr owner() : group_roles({cq::GroupRole::OWNER}) { } }; } // namespace matchers