File indexing completed on 2025-01-18 09:54:07
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED
0009 #define CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED
0010
0011 #include <catch2/matchers/catch_matchers.hpp>
0012 #include <catch2/internal/catch_stringref.hpp>
0013 #include <catch2/internal/catch_move_and_forward.hpp>
0014 #include <catch2/internal/catch_logical_traits.hpp>
0015
0016 #include <array>
0017 #include <algorithm>
0018 #include <string>
0019 #include <type_traits>
0020
0021 namespace Catch {
0022 namespace Matchers {
0023 class MatcherGenericBase : public MatcherUntypedBase {
0024 public:
0025 MatcherGenericBase() = default;
0026 ~MatcherGenericBase() override;
0027
0028 MatcherGenericBase(MatcherGenericBase const&) = default;
0029 MatcherGenericBase(MatcherGenericBase&&) = default;
0030
0031 MatcherGenericBase& operator=(MatcherGenericBase const&) = delete;
0032 MatcherGenericBase& operator=(MatcherGenericBase&&) = delete;
0033 };
0034
0035
0036 namespace Detail {
0037 template<std::size_t N, std::size_t M>
0038 std::array<void const*, N + M> array_cat(std::array<void const*, N> && lhs, std::array<void const*, M> && rhs) {
0039 std::array<void const*, N + M> arr{};
0040 std::copy_n(lhs.begin(), N, arr.begin());
0041 std::copy_n(rhs.begin(), M, arr.begin() + N);
0042 return arr;
0043 }
0044
0045 template<std::size_t N>
0046 std::array<void const*, N+1> array_cat(std::array<void const*, N> && lhs, void const* rhs) {
0047 std::array<void const*, N+1> arr{};
0048 std::copy_n(lhs.begin(), N, arr.begin());
0049 arr[N] = rhs;
0050 return arr;
0051 }
0052
0053 template<std::size_t N>
0054 std::array<void const*, N+1> array_cat(void const* lhs, std::array<void const*, N> && rhs) {
0055 std::array<void const*, N + 1> arr{ {lhs} };
0056 std::copy_n(rhs.begin(), N, arr.begin() + 1);
0057 return arr;
0058 }
0059
0060 template<typename T>
0061 using is_generic_matcher = std::is_base_of<
0062 Catch::Matchers::MatcherGenericBase,
0063 std::remove_cv_t<std::remove_reference_t<T>>
0064 >;
0065
0066 template<typename... Ts>
0067 using are_generic_matchers = Catch::Detail::conjunction<is_generic_matcher<Ts>...>;
0068
0069 template<typename T>
0070 using is_matcher = std::is_base_of<
0071 Catch::Matchers::MatcherUntypedBase,
0072 std::remove_cv_t<std::remove_reference_t<T>>
0073 >;
0074
0075
0076 template<std::size_t N, typename Arg>
0077 bool match_all_of(Arg&&, std::array<void const*, N> const&, std::index_sequence<>) {
0078 return true;
0079 }
0080
0081 template<typename T, typename... MatcherTs, std::size_t N, typename Arg, std::size_t Idx, std::size_t... Indices>
0082 bool match_all_of(Arg&& arg, std::array<void const*, N> const& matchers, std::index_sequence<Idx, Indices...>) {
0083 return static_cast<T const*>(matchers[Idx])->match(arg) && match_all_of<MatcherTs...>(arg, matchers, std::index_sequence<Indices...>{});
0084 }
0085
0086
0087 template<std::size_t N, typename Arg>
0088 bool match_any_of(Arg&&, std::array<void const*, N> const&, std::index_sequence<>) {
0089 return false;
0090 }
0091
0092 template<typename T, typename... MatcherTs, std::size_t N, typename Arg, std::size_t Idx, std::size_t... Indices>
0093 bool match_any_of(Arg&& arg, std::array<void const*, N> const& matchers, std::index_sequence<Idx, Indices...>) {
0094 return static_cast<T const*>(matchers[Idx])->match(arg) || match_any_of<MatcherTs...>(arg, matchers, std::index_sequence<Indices...>{});
0095 }
0096
0097 std::string describe_multi_matcher(StringRef combine, std::string const* descriptions_begin, std::string const* descriptions_end);
0098
0099 template<typename... MatcherTs, std::size_t... Idx>
0100 std::string describe_multi_matcher(StringRef combine, std::array<void const*, sizeof...(MatcherTs)> const& matchers, std::index_sequence<Idx...>) {
0101 std::array<std::string, sizeof...(MatcherTs)> descriptions {{
0102 static_cast<MatcherTs const*>(matchers[Idx])->toString()...
0103 }};
0104
0105 return describe_multi_matcher(combine, descriptions.data(), descriptions.data() + descriptions.size());
0106 }
0107
0108
0109 template<typename... MatcherTs>
0110 class MatchAllOfGeneric final : public MatcherGenericBase {
0111 public:
0112 MatchAllOfGeneric(MatchAllOfGeneric const&) = delete;
0113 MatchAllOfGeneric& operator=(MatchAllOfGeneric const&) = delete;
0114 MatchAllOfGeneric(MatchAllOfGeneric&&) = default;
0115 MatchAllOfGeneric& operator=(MatchAllOfGeneric&&) = default;
0116
0117 MatchAllOfGeneric(MatcherTs const&... matchers) : m_matchers{ {std::addressof(matchers)...} } {}
0118 explicit MatchAllOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {}
0119
0120 template<typename Arg>
0121 bool match(Arg&& arg) const {
0122 return match_all_of<MatcherTs...>(arg, m_matchers, std::index_sequence_for<MatcherTs...>{});
0123 }
0124
0125 std::string describe() const override {
0126 return describe_multi_matcher<MatcherTs...>(" and "_sr, m_matchers, std::index_sequence_for<MatcherTs...>{});
0127 }
0128
0129
0130
0131
0132 std::array<void const*, sizeof...( MatcherTs )> m_matchers;
0133
0134
0135
0136 template<typename... MatchersRHS>
0137 friend
0138 MatchAllOfGeneric<MatcherTs..., MatchersRHS...> operator && (
0139 MatchAllOfGeneric<MatcherTs...>&& lhs,
0140 MatchAllOfGeneric<MatchersRHS...>&& rhs) {
0141 return MatchAllOfGeneric<MatcherTs..., MatchersRHS...>{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))};
0142 }
0143
0144
0145 template<typename MatcherRHS>
0146 friend std::enable_if_t<is_matcher<MatcherRHS>::value,
0147 MatchAllOfGeneric<MatcherTs..., MatcherRHS>> operator && (
0148 MatchAllOfGeneric<MatcherTs...>&& lhs,
0149 MatcherRHS const& rhs) {
0150 return MatchAllOfGeneric<MatcherTs..., MatcherRHS>{array_cat(CATCH_MOVE(lhs.m_matchers), static_cast<void const*>(&rhs))};
0151 }
0152
0153
0154 template<typename MatcherLHS>
0155 friend std::enable_if_t<is_matcher<MatcherLHS>::value,
0156 MatchAllOfGeneric<MatcherLHS, MatcherTs...>> operator && (
0157 MatcherLHS const& lhs,
0158 MatchAllOfGeneric<MatcherTs...>&& rhs) {
0159 return MatchAllOfGeneric<MatcherLHS, MatcherTs...>{array_cat(static_cast<void const*>(std::addressof(lhs)), CATCH_MOVE(rhs.m_matchers))};
0160 }
0161 };
0162
0163
0164 template<typename... MatcherTs>
0165 class MatchAnyOfGeneric final : public MatcherGenericBase {
0166 public:
0167 MatchAnyOfGeneric(MatchAnyOfGeneric const&) = delete;
0168 MatchAnyOfGeneric& operator=(MatchAnyOfGeneric const&) = delete;
0169 MatchAnyOfGeneric(MatchAnyOfGeneric&&) = default;
0170 MatchAnyOfGeneric& operator=(MatchAnyOfGeneric&&) = default;
0171
0172 MatchAnyOfGeneric(MatcherTs const&... matchers) : m_matchers{ {std::addressof(matchers)...} } {}
0173 explicit MatchAnyOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {}
0174
0175 template<typename Arg>
0176 bool match(Arg&& arg) const {
0177 return match_any_of<MatcherTs...>(arg, m_matchers, std::index_sequence_for<MatcherTs...>{});
0178 }
0179
0180 std::string describe() const override {
0181 return describe_multi_matcher<MatcherTs...>(" or "_sr, m_matchers, std::index_sequence_for<MatcherTs...>{});
0182 }
0183
0184
0185
0186
0187
0188 std::array<void const*, sizeof...( MatcherTs )> m_matchers;
0189
0190
0191 template<typename... MatchersRHS>
0192 friend MatchAnyOfGeneric<MatcherTs..., MatchersRHS...> operator || (
0193 MatchAnyOfGeneric<MatcherTs...>&& lhs,
0194 MatchAnyOfGeneric<MatchersRHS...>&& rhs) {
0195 return MatchAnyOfGeneric<MatcherTs..., MatchersRHS...>{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))};
0196 }
0197
0198
0199 template<typename MatcherRHS>
0200 friend std::enable_if_t<is_matcher<MatcherRHS>::value,
0201 MatchAnyOfGeneric<MatcherTs..., MatcherRHS>> operator || (
0202 MatchAnyOfGeneric<MatcherTs...>&& lhs,
0203 MatcherRHS const& rhs) {
0204 return MatchAnyOfGeneric<MatcherTs..., MatcherRHS>{array_cat(CATCH_MOVE(lhs.m_matchers), static_cast<void const*>(std::addressof(rhs)))};
0205 }
0206
0207
0208 template<typename MatcherLHS>
0209 friend std::enable_if_t<is_matcher<MatcherLHS>::value,
0210 MatchAnyOfGeneric<MatcherLHS, MatcherTs...>> operator || (
0211 MatcherLHS const& lhs,
0212 MatchAnyOfGeneric<MatcherTs...>&& rhs) {
0213 return MatchAnyOfGeneric<MatcherLHS, MatcherTs...>{array_cat(static_cast<void const*>(std::addressof(lhs)), CATCH_MOVE(rhs.m_matchers))};
0214 }
0215 };
0216
0217
0218 template<typename MatcherT>
0219 class MatchNotOfGeneric final : public MatcherGenericBase {
0220 MatcherT const& m_matcher;
0221
0222 public:
0223 MatchNotOfGeneric(MatchNotOfGeneric const&) = delete;
0224 MatchNotOfGeneric& operator=(MatchNotOfGeneric const&) = delete;
0225 MatchNotOfGeneric(MatchNotOfGeneric&&) = default;
0226 MatchNotOfGeneric& operator=(MatchNotOfGeneric&&) = default;
0227
0228 explicit MatchNotOfGeneric(MatcherT const& matcher) : m_matcher{matcher} {}
0229
0230 template<typename Arg>
0231 bool match(Arg&& arg) const {
0232 return !m_matcher.match(arg);
0233 }
0234
0235 std::string describe() const override {
0236 return "not " + m_matcher.toString();
0237 }
0238
0239
0240 friend MatcherT const& operator ! (MatchNotOfGeneric<MatcherT> const& matcher) {
0241 return matcher.m_matcher;
0242 }
0243 };
0244 }
0245
0246
0247
0248 template<typename MatcherLHS, typename MatcherRHS>
0249 std::enable_if_t<Detail::are_generic_matchers<MatcherLHS, MatcherRHS>::value, Detail::MatchAllOfGeneric<MatcherLHS, MatcherRHS>>
0250 operator && (MatcherLHS const& lhs, MatcherRHS const& rhs) {
0251 return { lhs, rhs };
0252 }
0253
0254 template<typename MatcherLHS, typename MatcherRHS>
0255 std::enable_if_t<Detail::are_generic_matchers<MatcherLHS, MatcherRHS>::value, Detail::MatchAnyOfGeneric<MatcherLHS, MatcherRHS>>
0256 operator || (MatcherLHS const& lhs, MatcherRHS const& rhs) {
0257 return { lhs, rhs };
0258 }
0259
0260
0261 template<typename MatcherT>
0262 std::enable_if_t<Detail::is_generic_matcher<MatcherT>::value, Detail::MatchNotOfGeneric<MatcherT>>
0263 operator ! (MatcherT const& matcher) {
0264 return Detail::MatchNotOfGeneric<MatcherT>{matcher};
0265 }
0266
0267
0268
0269 template<typename MatcherLHS, typename ArgRHS>
0270 std::enable_if_t<Detail::is_generic_matcher<MatcherLHS>::value, Detail::MatchAllOfGeneric<MatcherLHS, MatcherBase<ArgRHS>>>
0271 operator && (MatcherLHS const& lhs, MatcherBase<ArgRHS> const& rhs) {
0272 return { lhs, rhs };
0273 }
0274
0275 template<typename ArgLHS, typename MatcherRHS>
0276 std::enable_if_t<Detail::is_generic_matcher<MatcherRHS>::value, Detail::MatchAllOfGeneric<MatcherBase<ArgLHS>, MatcherRHS>>
0277 operator && (MatcherBase<ArgLHS> const& lhs, MatcherRHS const& rhs) {
0278 return { lhs, rhs };
0279 }
0280
0281 template<typename MatcherLHS, typename ArgRHS>
0282 std::enable_if_t<Detail::is_generic_matcher<MatcherLHS>::value, Detail::MatchAnyOfGeneric<MatcherLHS, MatcherBase<ArgRHS>>>
0283 operator || (MatcherLHS const& lhs, MatcherBase<ArgRHS> const& rhs) {
0284 return { lhs, rhs };
0285 }
0286
0287 template<typename ArgLHS, typename MatcherRHS>
0288 std::enable_if_t<Detail::is_generic_matcher<MatcherRHS>::value, Detail::MatchAnyOfGeneric<MatcherBase<ArgLHS>, MatcherRHS>>
0289 operator || (MatcherBase<ArgLHS> const& lhs, MatcherRHS const& rhs) {
0290 return { lhs, rhs };
0291 }
0292
0293 }
0294 }
0295
0296 #endif