From bc524d70253a4ab2fe40c3ca3e5666e267c0a4d1 Mon Sep 17 00:00:00 2001 From: Lexi Winter Date: Sun, 29 Jun 2025 19:25:29 +0100 Subject: import catch2 3.8.1 --- src/catch2/matchers/catch_matchers_templated.hpp | 296 +++++++++++++++++++++++ 1 file changed, 296 insertions(+) create mode 100644 src/catch2/matchers/catch_matchers_templated.hpp (limited to 'src/catch2/matchers/catch_matchers_templated.hpp') diff --git a/src/catch2/matchers/catch_matchers_templated.hpp b/src/catch2/matchers/catch_matchers_templated.hpp new file mode 100644 index 0000000..ba0661a --- /dev/null +++ b/src/catch2/matchers/catch_matchers_templated.hpp @@ -0,0 +1,296 @@ + +// Copyright Catch2 Authors +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +// SPDX-License-Identifier: BSL-1.0 +#ifndef CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED +#define CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace Catch { +namespace Matchers { + class MatcherGenericBase : public MatcherUntypedBase { + public: + MatcherGenericBase() = default; + ~MatcherGenericBase() override; // = default; + + MatcherGenericBase(MatcherGenericBase const&) = default; + MatcherGenericBase(MatcherGenericBase&&) = default; + + MatcherGenericBase& operator=(MatcherGenericBase const&) = delete; + MatcherGenericBase& operator=(MatcherGenericBase&&) = delete; + }; + + + namespace Detail { + template + std::array array_cat(std::array && lhs, std::array && rhs) { + std::array arr{}; + std::copy_n(lhs.begin(), N, arr.begin()); + std::copy_n(rhs.begin(), M, arr.begin() + N); + return arr; + } + + template + std::array array_cat(std::array && lhs, void const* rhs) { + std::array arr{}; + std::copy_n(lhs.begin(), N, arr.begin()); + arr[N] = rhs; + return arr; + } + + template + std::array array_cat(void const* lhs, std::array && rhs) { + std::array arr{ {lhs} }; + std::copy_n(rhs.begin(), N, arr.begin() + 1); + return arr; + } + + template + using is_generic_matcher = std::is_base_of< + Catch::Matchers::MatcherGenericBase, + std::remove_cv_t> + >; + + template + using are_generic_matchers = Catch::Detail::conjunction...>; + + template + using is_matcher = std::is_base_of< + Catch::Matchers::MatcherUntypedBase, + std::remove_cv_t> + >; + + + template + bool match_all_of(Arg&&, std::array const&, std::index_sequence<>) { + return true; + } + + template + bool match_all_of(Arg&& arg, std::array const& matchers, std::index_sequence) { + return static_cast(matchers[Idx])->match(arg) && match_all_of(arg, matchers, std::index_sequence{}); + } + + + template + bool match_any_of(Arg&&, std::array const&, std::index_sequence<>) { + return false; + } + + template + bool match_any_of(Arg&& arg, std::array const& matchers, std::index_sequence) { + return static_cast(matchers[Idx])->match(arg) || match_any_of(arg, matchers, std::index_sequence{}); + } + + std::string describe_multi_matcher(StringRef combine, std::string const* descriptions_begin, std::string const* descriptions_end); + + template + std::string describe_multi_matcher(StringRef combine, std::array const& matchers, std::index_sequence) { + std::array descriptions {{ + static_cast(matchers[Idx])->toString()... + }}; + + return describe_multi_matcher(combine, descriptions.data(), descriptions.data() + descriptions.size()); + } + + + template + class MatchAllOfGeneric final : public MatcherGenericBase { + public: + MatchAllOfGeneric(MatchAllOfGeneric const&) = delete; + MatchAllOfGeneric& operator=(MatchAllOfGeneric const&) = delete; + MatchAllOfGeneric(MatchAllOfGeneric&&) = default; + MatchAllOfGeneric& operator=(MatchAllOfGeneric&&) = default; + + MatchAllOfGeneric(MatcherTs const&... matchers) : m_matchers{ {std::addressof(matchers)...} } {} + explicit MatchAllOfGeneric(std::array matchers) : m_matchers{matchers} {} + + template + bool match(Arg&& arg) const { + return match_all_of(arg, m_matchers, std::index_sequence_for{}); + } + + std::string describe() const override { + return describe_multi_matcher(" and "_sr, m_matchers, std::index_sequence_for{}); + } + + // Has to be public to enable the concatenating operators + // below, because they are not friend of the RHS, only LHS, + // and thus cannot access private fields of RHS + std::array m_matchers; + + + //! Avoids type nesting for `GenericAllOf && GenericAllOf` case + template + friend + MatchAllOfGeneric operator && ( + MatchAllOfGeneric&& lhs, + MatchAllOfGeneric&& rhs) { + return MatchAllOfGeneric{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))}; + } + + //! Avoids type nesting for `GenericAllOf && some matcher` case + template + friend std::enable_if_t::value, + MatchAllOfGeneric> operator && ( + MatchAllOfGeneric&& lhs, + MatcherRHS const& rhs) { + return MatchAllOfGeneric{array_cat(CATCH_MOVE(lhs.m_matchers), static_cast(&rhs))}; + } + + //! Avoids type nesting for `some matcher && GenericAllOf` case + template + friend std::enable_if_t::value, + MatchAllOfGeneric> operator && ( + MatcherLHS const& lhs, + MatchAllOfGeneric&& rhs) { + return MatchAllOfGeneric{array_cat(static_cast(std::addressof(lhs)), CATCH_MOVE(rhs.m_matchers))}; + } + }; + + + template + class MatchAnyOfGeneric final : public MatcherGenericBase { + public: + MatchAnyOfGeneric(MatchAnyOfGeneric const&) = delete; + MatchAnyOfGeneric& operator=(MatchAnyOfGeneric const&) = delete; + MatchAnyOfGeneric(MatchAnyOfGeneric&&) = default; + MatchAnyOfGeneric& operator=(MatchAnyOfGeneric&&) = default; + + MatchAnyOfGeneric(MatcherTs const&... matchers) : m_matchers{ {std::addressof(matchers)...} } {} + explicit MatchAnyOfGeneric(std::array matchers) : m_matchers{matchers} {} + + template + bool match(Arg&& arg) const { + return match_any_of(arg, m_matchers, std::index_sequence_for{}); + } + + std::string describe() const override { + return describe_multi_matcher(" or "_sr, m_matchers, std::index_sequence_for{}); + } + + + // Has to be public to enable the concatenating operators + // below, because they are not friend of the RHS, only LHS, + // and thus cannot access private fields of RHS + std::array m_matchers; + + //! Avoids type nesting for `GenericAnyOf || GenericAnyOf` case + template + friend MatchAnyOfGeneric operator || ( + MatchAnyOfGeneric&& lhs, + MatchAnyOfGeneric&& rhs) { + return MatchAnyOfGeneric{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))}; + } + + //! Avoids type nesting for `GenericAnyOf || some matcher` case + template + friend std::enable_if_t::value, + MatchAnyOfGeneric> operator || ( + MatchAnyOfGeneric&& lhs, + MatcherRHS const& rhs) { + return MatchAnyOfGeneric{array_cat(CATCH_MOVE(lhs.m_matchers), static_cast(std::addressof(rhs)))}; + } + + //! Avoids type nesting for `some matcher || GenericAnyOf` case + template + friend std::enable_if_t::value, + MatchAnyOfGeneric> operator || ( + MatcherLHS const& lhs, + MatchAnyOfGeneric&& rhs) { + return MatchAnyOfGeneric{array_cat(static_cast(std::addressof(lhs)), CATCH_MOVE(rhs.m_matchers))}; + } + }; + + + template + class MatchNotOfGeneric final : public MatcherGenericBase { + MatcherT const& m_matcher; + + public: + MatchNotOfGeneric(MatchNotOfGeneric const&) = delete; + MatchNotOfGeneric& operator=(MatchNotOfGeneric const&) = delete; + MatchNotOfGeneric(MatchNotOfGeneric&&) = default; + MatchNotOfGeneric& operator=(MatchNotOfGeneric&&) = default; + + explicit MatchNotOfGeneric(MatcherT const& matcher) : m_matcher{matcher} {} + + template + bool match(Arg&& arg) const { + return !m_matcher.match(arg); + } + + std::string describe() const override { + return "not " + m_matcher.toString(); + } + + //! Negating negation can just unwrap and return underlying matcher + friend MatcherT const& operator ! (MatchNotOfGeneric const& matcher) { + return matcher.m_matcher; + } + }; + } // namespace Detail + + + // compose only generic matchers + template + std::enable_if_t::value, Detail::MatchAllOfGeneric> + operator && (MatcherLHS const& lhs, MatcherRHS const& rhs) { + return { lhs, rhs }; + } + + template + std::enable_if_t::value, Detail::MatchAnyOfGeneric> + operator || (MatcherLHS const& lhs, MatcherRHS const& rhs) { + return { lhs, rhs }; + } + + //! Wrap provided generic matcher in generic negator + template + std::enable_if_t::value, Detail::MatchNotOfGeneric> + operator ! (MatcherT const& matcher) { + return Detail::MatchNotOfGeneric{matcher}; + } + + + // compose mixed generic and non-generic matchers + template + std::enable_if_t::value, Detail::MatchAllOfGeneric>> + operator && (MatcherLHS const& lhs, MatcherBase const& rhs) { + return { lhs, rhs }; + } + + template + std::enable_if_t::value, Detail::MatchAllOfGeneric, MatcherRHS>> + operator && (MatcherBase const& lhs, MatcherRHS const& rhs) { + return { lhs, rhs }; + } + + template + std::enable_if_t::value, Detail::MatchAnyOfGeneric>> + operator || (MatcherLHS const& lhs, MatcherBase const& rhs) { + return { lhs, rhs }; + } + + template + std::enable_if_t::value, Detail::MatchAnyOfGeneric, MatcherRHS>> + operator || (MatcherBase const& lhs, MatcherRHS const& rhs) { + return { lhs, rhs }; + } + +} // namespace Matchers +} // namespace Catch + +#endif // CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED -- cgit v1.2.3