[boost][range] - Improved handling of temporary ranges in range algorithms.

[SVN r63904]
This commit is contained in:
Neil Groves
2010-07-12 00:14:07 +00:00
parent 74a01a4487
commit 5bb66037d3
3 changed files with 189 additions and 8 deletions

View File

@ -15,19 +15,129 @@
#include <boost/assign.hpp> #include <boost/assign.hpp>
#include <boost/range/algorithm_ext.hpp> #include <boost/range/algorithm_ext.hpp>
#include <boost/range/sub_range.hpp>
#include <algorithm> #include <algorithm>
#include <list> #include <list>
#include <set> #include <set>
#include <vector> #include <vector>
#include <functional>
namespace boost namespace boost
{ {
namespace range3
{
namespace concept
{
template<class Range>
class PopFrontSubRange
{
public:
void constraints()
{
Range copied_range(*m_range);
BOOST_DEDUCED_TYPENAME range_value<Range>::type v = copied_range.front();
copied_range.pop_front();
}
private:
Range* m_range;
};
template<class Range>
class PopBackSubRange
{
public:
void constraints()
{
Range copied_range(*m_range);
BOOST_DEDUCED_TYPENAME range_value<Range>::type v = copied_range.back();
copied_range.pop_back();
}
private:
Range* m_range;
};
} // namespace concept
namespace adaptor
{
template<class Range, class Pred>
class adjacent_filter_adaptor
: private boost::sub_range<Range>
, private Pred
{
public:
typedef boost::sub_range<Range> range_t;
typedef Pred pred_t;
typedef typename range_t::value_type value_type;
using range_t::reference;
using range_t::const_reference;
using range_t::empty;
using range_t::front;
using range_t::back;
adjacent_filter_adaptor(Range& rng, Pred pred)
: range_t(rng)
, pred_t(pred)
{
}
void pop_front()
{
BOOST_ASSERT( !empty() );
const value_type& old_front = front();
range_t::pop_front();
while (!empty() && !pred_t::operator()(front(), old_front))
range_t::pop_front();
}
void pop_back()
{
BOOST_ASSERT( !empty() );
const value_type& old_back = back();
range_t::pop_back();
while (!empty() && !pred_t::operator()(old_back, back()))
range_t::pop_back();
}
};
template<class Range>
class unique_adaptor
: public adjacent_filter_adaptor<Range, std::not_equal_to< typename range_value<Range>::type > >
{
typedef adjacent_filter_adaptor<Range, std::not_equal_to< typename range_value<Range>::type > > base_t;
public:
typedef std::not_equal_to< typename range_value<Range>::type > pred_t;
explicit unique_adaptor(Range& rng) : base_t(rng, pred_t()) {}
};
}
}
namespace namespace
{ {
template< class Container >
void new_uniqued_adaptor_test(Container& c)
{
std::vector<int> test_result1;
boost::range3::adaptor::unique_adaptor<Container> rng(c);
while (!rng.empty())
{
test_result1.push_back(rng.front());
rng.pop_front();
}
std::vector<int> test_result2;
boost::push_back(test_result2, adaptors::unique(c));
BOOST_CHECK_EQUAL_COLLECTIONS(
test_result1.begin(), test_result1.end(),
test_result2.begin(), test_result2.end()
);
}
template< class Container > template< class Container >
void uniqued_test_impl( Container& c ) void uniqued_test_impl( Container& c )
{ {
new_uniqued_adaptor_test(c);
using namespace boost::adaptors; using namespace boost::adaptors;
std::vector< int > test_result1; std::vector< int > test_result1;

View File

@ -17,6 +17,7 @@
# pragma warn -8057 // unused argument argc/argv in Boost.Test # pragma warn -8057 // unused argument argc/argv in Boost.Test
#endif #endif
#include <boost/array.hpp>
#include <boost/range/as_array.hpp> #include <boost/range/as_array.hpp>
#include <boost/range/as_literal.hpp> #include <boost/range/as_literal.hpp>
#include <boost/range/functions.hpp> #include <boost/range/functions.hpp>
@ -29,6 +30,34 @@
#include <fstream> #include <fstream>
#include <algorithm> #include <algorithm>
namespace
{
template< class CharT, std::size_t Length >
class test_string
{
public:
typedef CharT value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef std::size_t size_type;
typedef value_type array_t[Length];
typedef const value_type const_array_t[Length];
explicit test_string(const CharT literal_sz[])
{
std::copy(literal_sz, literal_sz + Length, m_buffer.data());
m_buffer[Length] = value_type();
}
const_pointer const_sz() const { return m_buffer.data(); }
pointer mutable_sz() { return m_buffer.data(); }
private:
typedef boost::array<value_type, Length + 1> buffer_t;
buffer_t m_buffer;
};
}
template< class T > template< class T >
inline BOOST_DEDUCED_TYPENAME boost::range_iterator<T>::type inline BOOST_DEDUCED_TYPENAME boost::range_iterator<T>::type
str_begin( T& r ) str_begin( T& r )
@ -105,11 +134,15 @@ void check_char()
{ {
typedef char* char_iterator_t; typedef char* char_iterator_t;
typedef char char_array_t[10]; typedef char char_array_t[10];
const char* char_s = "a string";
char my_string[] = "another string"; test_string<char, 8> a_string("a string");
test_string<char, 14> another_string("another string");
const char* char_s = a_string.const_sz();
char my_string[] = "another_string";
const char my_const_string[] = "another string"; const char my_const_string[] = "another string";
const unsigned my_string_length = 14; const unsigned my_string_length = 14;
char* char_s2 = "a string"; char* char_s2 = a_string.mutable_sz();
BOOST_STATIC_ASSERT(( is_same< range_value<char_iterator_t>::type, BOOST_STATIC_ASSERT(( is_same< range_value<char_iterator_t>::type,
detail::iterator_traits<char_iterator_t>::value_type>::value )); detail::iterator_traits<char_iterator_t>::value_type>::value ));
@ -181,10 +214,14 @@ void check_string()
check_char(); check_char();
#ifndef BOOST_NO_STD_WSTRING #ifndef BOOST_NO_STD_WSTRING
typedef wchar_t* wchar_iterator_t; typedef wchar_t* wchar_iterator_t;
const wchar_t* char_ws = L"a wide string";
test_string<wchar_t, 13> a_wide_string(L"a wide string");
test_string<wchar_t, 19> another_wide_string(L"another wide string");
const wchar_t* char_ws = a_wide_string.const_sz();
wchar_t my_wstring[] = L"another wide string"; wchar_t my_wstring[] = L"another wide string";
wchar_t* char_ws2 = L"a wide string"; wchar_t* char_ws2 = a_wide_string.mutable_sz();
BOOST_STATIC_ASSERT(( is_same< range_value<wchar_iterator_t>::type, BOOST_STATIC_ASSERT(( is_same< range_value<wchar_iterator_t>::type,
detail::iterator_traits<wchar_iterator_t>::value_type>::value )); detail::iterator_traits<wchar_iterator_t>::value_type>::value ));
@ -203,12 +240,17 @@ void check_string()
BOOST_CHECK_EQUAL( sz, std::char_traits<wchar_t>::length( char_ws ) ); BOOST_CHECK_EQUAL( sz, std::char_traits<wchar_t>::length( char_ws ) );
wchar_t to_search = L'n'; wchar_t to_search = L'n';
BOOST_CHECK( find( char_ws, to_search ) != str_end(char_ws) ); BOOST_CHECK( find( char_ws, to_search ) != str_end(char_ws) );
BOOST_CHECK( find( char_ws2, to_search ) != str_end(char_ws2) );
#if BOOST_WORKAROUND(_MSC_VER, BOOST_TESTED_AT(1300)) #if BOOST_WORKAROUND(_MSC_VER, BOOST_TESTED_AT(1300))
BOOST_CHECK( find( my_wstring, to_search ) != str_end(my_wstring) ); BOOST_CHECK( find( my_wstring, to_search ) != str_end(my_wstring) );
#else
boost::ignore_unused_variable_warning( my_wstring );
#endif #endif
#endif #endif

View File

@ -0,0 +1,29 @@
// Boost.Range library
//
// Copyright Neil Groves 2010. Use, modification and
// distribution is subject to 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)
//
//
// For more information, see http://www.boost.org/libs/range/
//
#ifndef BOOST_RANGE_TEST_TEST_FUNCTION_TRUE_PREDICATE_HPP_INCLUDED
#define BOOST_RANGE_TEST_TEST_FUNCTION_TRUE_PREDICATE_HPP_INCLUDED
namespace boost
{
namespace range_test_function
{
struct true_predicate
{
typedef bool result_type;
bool operator()() const { return true; }
template<class Arg> bool operator()(Arg) const { return true; }
template<class Arg1, class Arg2> bool operator()(Arg1,Arg2) const { return true; }
};
}
}
#endif // include guard