forked from boostorg/algorithm
		
	
		
			
				
	
	
		
			131 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			131 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* 
 | 
						|
   Copyright (c) Marshall Clow 2013
 | 
						|
 | 
						|
   Distributed under the Boost Software License, Version 1.0. (See accompanying
 | 
						|
   file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | 
						|
*/
 | 
						|
 | 
						|
/// \file  equal.hpp
 | 
						|
/// \brief Determines if one 
 | 
						|
/// \author Marshall Clow
 | 
						|
 | 
						|
#ifndef BOOST_ALGORITHM_IS_PERMUTATION_HPP
 | 
						|
#define BOOST_ALGORITHM_IS_PERMUTATION_HPP
 | 
						|
 | 
						|
#include <algorithm>
 | 
						|
#include <functional>	// for std::equal_to
 | 
						|
 | 
						|
namespace boost { namespace algorithm {
 | 
						|
 | 
						|
namespace detail {
 | 
						|
 | 
						|
	template <class T1, class T2>
 | 
						|
	struct is_perm_eq : public std::binary_function<T1, T2, bool> {
 | 
						|
		bool operator () ( const T1& v1, const T2& v2 ) const { return v1 == v2 ;}
 | 
						|
		};
 | 
						|
	
 | 
						|
 | 
						|
	template <class RandomAccessIterator1, class RandomAccessIterator2, class BinaryPredicate>
 | 
						|
	bool is_permutation ( RandomAccessIterator1 first1, RandomAccessIterator1 last1, 
 | 
						|
				 RandomAccessIterator2 first2, RandomAccessIterator2 last2, BinaryPredicate pred,
 | 
						|
				 std::random_access_iterator_tag, std::random_access_iterator_tag )
 | 
						|
	{
 | 
						|
	//	Random-access iterators let is check the sizes in constant time
 | 
						|
		if ( std::distance ( first1, last1 ) != std::distance ( first2, last2 ))
 | 
						|
			return false;
 | 
						|
	// If we know that the sequences are the same size, the original version is fine
 | 
						|
		return std::is_permutation ( first1, last1, first2, pred );
 | 
						|
	}
 | 
						|
 | 
						|
 | 
						|
	template<class ForwardIterator1, class ForwardIterator2, class BinaryPredicate>
 | 
						|
	bool is_permutation (
 | 
						|
				ForwardIterator1 first1, ForwardIterator1 last1,
 | 
						|
				ForwardIterator2 first2, ForwardIterator2 last2, 
 | 
						|
				BinaryPredicate pred,
 | 
						|
				std::forward_iterator_tag, std::forward_iterator_tag )
 | 
						|
	{
 | 
						|
 | 
						|
	//	Look for common prefix
 | 
						|
		for (; first1 != last1 && first2 != last2; ++first1, ++first2)
 | 
						|
			if (!pred(*first1, *first2))
 | 
						|
				goto not_done;
 | 
						|
	//	We've reached the end of one of the sequences without a mismatch.
 | 
						|
		return first1 == last1 && first2 == last2;
 | 
						|
	not_done:
 | 
						|
 | 
						|
	//	Check and make sure that we have the same # of elements left
 | 
						|
		typedef typename std::iterator_traits<ForwardIterator1>::difference_type diff1_t;
 | 
						|
		diff1_t len1 = _VSTD::distance(first1, last1);
 | 
						|
		typedef typename std::iterator_traits<ForwardIterator2>::difference_type diff2_t;
 | 
						|
		diff2_t len2 = _VSTD::distance(first2, last2);
 | 
						|
		if (len1 != len2)
 | 
						|
			return false;
 | 
						|
 | 
						|
	//	For each element in [f1, l1) see if there are the 
 | 
						|
	//	same number of equal elements in [f2, l2)
 | 
						|
		for ( ForwardIterator1 i = first1; i != last1; ++i )
 | 
						|
		{
 | 
						|
		//	Have we already counted this value?
 | 
						|
			ForwardIterator1 j;
 | 
						|
			for ( j = first1; j != i; ++j )
 | 
						|
				if (pred(*j, *i))
 | 
						|
					break;
 | 
						|
			if ( j == i )	// didn't find it...
 | 
						|
			{
 | 
						|
			//	Count number of *i in [f2, l2)
 | 
						|
				diff1_t c2 = 0;
 | 
						|
				for ( ForwardIterator2 iter2 = first2; iter2 != last2; ++iter2 )
 | 
						|
					if (pred(*i, *iter2))
 | 
						|
						++c2;
 | 
						|
				if (c2 == 0)
 | 
						|
					return false;
 | 
						|
 | 
						|
			//	Count number of *i in [i, l1)
 | 
						|
				diff1_t c1 = 0;
 | 
						|
				for (_ForwardIterator1 iter1 = i; iter1 != last1; ++iter1 )
 | 
						|
					if (pred(*i, *iter1))
 | 
						|
						++c1;
 | 
						|
				if (c1 != c2)
 | 
						|
					return false;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
template<class ForwardIterator1, class ForwardIterator2, class BinaryPredicate>
 | 
						|
bool is_permutation (
 | 
						|
			ForwardIterator1 first1, ForwardIterator1 last1,
 | 
						|
			ForwardIterator2 first2, ForwardIterator2 last2, 
 | 
						|
			BinaryPredicate pred )
 | 
						|
{
 | 
						|
	return boost::algorithm::detail::is_permutation ( 
 | 
						|
		first1, last1, first2, last2, pred,
 | 
						|
		typename std::iterator_traits<ForwardIterator1>::iterator_category (),
 | 
						|
		typename std::iterator_traits<ForwardIterator2>::iterator_category ());
 | 
						|
}
 | 
						|
 | 
						|
template<class ForwardIterator1, class ForwardIterator2>
 | 
						|
bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1,
 | 
						|
					  ForwardIterator2 first2, ForwardIterator2 last2 )
 | 
						|
{
 | 
						|
    typedef typename iterator_traits<_ForwardIterator1>::value_type value1_t;
 | 
						|
    typedef typename iterator_traits<_ForwardIterator2>::value_type value2_t;
 | 
						|
    return boost::algorithm::detail::is_permutation ( 
 | 
						|
    		first1, last1, first2, last2, 
 | 
						|
      		boost::algorithm::detail::is_perm_eq<
 | 
						|
				typename std::iterator_traits<InputIterator1>::value_type,
 | 
						|
				typename std::iterator_traits<InputIterator2>::value_type> (),
 | 
						|
			typename std::iterator_traits<ForwardIterator1>::iterator_category (),
 | 
						|
			typename std::iterator_traits<ForwardIterator2>::iterator_category ());
 | 
						|
}
 | 
						|
 | 
						|
//	There are already range-based versions of these.
 | 
						|
 | 
						|
}} // namespace boost and algorithm
 | 
						|
 | 
						|
#endif // BOOST_ALGORITHM_IS_PERMUTATION_HPP
 |