| 2620 | struct UnorderedEqualsMatcher : MatcherBase<std::vector<T>> { |
| 2621 | UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {} |
| 2622 | bool match(std::vector<T> const& vec) const override { |
| 2623 | // Note: This is a reimplementation of std::is_permutation, |
| 2624 | // because I don't want to include <algorithm> inside the common path |
| 2625 | if (m_target.size() != vec.size()) { |
| 2626 | return false; |
| 2627 | } |
| 2628 | auto lfirst = m_target.begin(), llast = m_target.end(); |
| 2629 | auto rfirst = vec.begin(), rlast = vec.end(); |
| 2630 | // Cut common prefix to optimize checking of permuted parts |
| 2631 | while (lfirst != llast && *lfirst != *rfirst) { |
| 2632 | ++lfirst; ++rfirst; |
| 2633 | } |
| 2634 | if (lfirst == llast) { |
| 2635 | return true; |
| 2636 | } |
| 2637 | |
| 2638 | for (auto mid = lfirst; mid != llast; ++mid) { |
| 2639 | // Skip already counted items |
| 2640 | if (Detail::contains(lfirst, mid, *mid)) { |
| 2641 | continue; |
| 2642 | } |
| 2643 | size_t num_vec = Detail::count(rfirst, rlast, *mid); |
| 2644 | if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) { |
| 2645 | return false; |
| 2646 | } |
| 2647 | } |
| 2648 | |
| 2649 | return true; |
| 2650 | } |
| 2651 | |
| 2652 | std::string describe() const override { |
| 2653 | return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); |