@@ -130,6 +130,15 @@ template <typename RelOp> constexpr auto to_string() {
130130 return " !=" _ctst;
131131 }
132132}
133+
134+ template <typename Field, typename Msg>
135+ [[nodiscard]] constexpr static auto extract_field (Msg const &msg) {
136+ if constexpr (stdx::range<Msg>) {
137+ return Field::extract (msg);
138+ } else {
139+ return msg.get (Field{});
140+ }
141+ }
133142} // namespace detail
134143
135144template <typename RelOp, typename Field, typename Field::type ExpectedValue>
@@ -138,7 +147,7 @@ struct rel_matcher_t {
138147
139148 template <typename MsgType>
140149 [[nodiscard]] constexpr auto operator ()(MsgType const &msg) const -> bool {
141- return RelOp{}(extract_field (msg), ExpectedValue);
150+ return RelOp{}(detail:: extract_field<Field> (msg), ExpectedValue);
142151 }
143152
144153 [[nodiscard]] constexpr auto describe () const {
@@ -157,12 +166,12 @@ struct rel_matcher_t {
157166 [[nodiscard]] constexpr auto describe_match (MsgType const &msg) const {
158167 if constexpr (std::integral<typename Field::type>) {
159168 return stdx::ct_format<" {} (0x{:x}) {} 0x{:x}" >(
160- Field::name, extract_field (msg), detail::to_string<RelOp>( ),
161- stdx::ct<ExpectedValue>());
169+ Field::name, detail::extract_field<Field>(msg ),
170+ detail::to_string<RelOp>(), stdx::ct<ExpectedValue>());
162171 } else {
163172 return stdx::ct_format<" {} ({}) {} {}" >(
164- Field::name, extract_field (msg), detail::to_string<RelOp>( ),
165- stdx::ct<ExpectedValue>());
173+ Field::name, detail::extract_field<Field>(msg ),
174+ detail::to_string<RelOp>(), stdx::ct<ExpectedValue>());
166175 }
167176 }
168177
@@ -180,15 +189,6 @@ struct rel_matcher_t {
180189 return ExpectedValue == OtherValue or
181190 RelOp{}(ExpectedValue, OtherValue);
182191 }
183-
184- template <typename Msg>
185- [[nodiscard]] constexpr static auto extract_field (Msg const &msg) {
186- if constexpr (stdx::range<Msg>) {
187- return Field::extract (msg);
188- } else {
189- return msg.get (Field{});
190- }
191- }
192192};
193193
194194template <typename Field, auto ExpectedValue>
@@ -341,4 +341,31 @@ template <typename Field>
341341using equal_default_t = equal_to_t <Field, Field::default_value>;
342342template <typename Field>
343343constexpr auto equal_default = equal_default_t <Field>{};
344+
345+ template <typename Field, auto P> struct pred_matcher_t {
346+ using is_matcher = void ;
347+
348+ template <typename MsgType>
349+ [[nodiscard]] constexpr auto operator ()(MsgType const &msg) const -> bool {
350+ return P (detail::extract_field<Field>(msg));
351+ }
352+
353+ [[nodiscard]] constexpr auto describe () const {
354+ return stdx::ct_format<" <predicate>({})" >(Field::name);
355+ }
356+
357+ template <typename MsgType>
358+ [[nodiscard]] constexpr auto describe_match (MsgType const &msg) const {
359+ if constexpr (std::integral<typename Field::type>) {
360+ return stdx::ct_format<" <predicate>({}(0x{:x}))" >(
361+ Field::name, detail::extract_field<Field>(msg));
362+ } else {
363+ return stdx::ct_format<" <predicate>({}({}))" >(
364+ Field::name, detail::extract_field<Field>(msg));
365+ }
366+ }
367+ };
368+
369+ template <typename Field, auto P>
370+ constexpr auto pred_matcher = pred_matcher_t <Field, P>{};
344371} // namespace msg
0 commit comments