Merge branch 'develop' - small fixes in addition to a more major fix for adaptors

producing iterators that did not have default constructors.
This commit is contained in:
Neil Groves
2014-06-16 22:51:08 +01:00
80 changed files with 340 additions and 91 deletions
+17 -9
View File
@@ -12,6 +12,7 @@
#define BOOST_RANGE_ADAPTOR_FILTERED_HPP
#include <boost/range/adaptor/argument_fwd.hpp>
#include <boost/range/detail/default_constructible_unary_fn.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/range/concepts.hpp>
#include <boost/iterator/filter_iterator.hpp>
@@ -23,21 +24,28 @@ namespace boost
template< class P, class R >
struct filtered_range :
boost::iterator_range<
boost::filter_iterator< P,
BOOST_DEDUCED_TYPENAME range_iterator<R>::type
boost::filter_iterator<
typename default_constructible_unary_fn_gen<P, bool>::type,
typename range_iterator<R>::type
>
>
{
private:
typedef boost::iterator_range<
boost::filter_iterator< P,
BOOST_DEDUCED_TYPENAME range_iterator<R>::type
>
> base;
boost::filter_iterator<
typename default_constructible_unary_fn_gen<P, bool>::type,
typename range_iterator<R>::type
>
> base;
public:
filtered_range( P p, R& r )
: base( make_filter_iterator( p, boost::begin(r), boost::end(r) ),
make_filter_iterator( p, boost::end(r), boost::end(r) ) )
typedef typename default_constructible_unary_fn_gen<P, bool>::type
pred_t;
filtered_range(P p, R& r)
: base(make_filter_iterator(pred_t(p),
boost::begin(r), boost::end(r)),
make_filter_iterator(pred_t(p),
boost::end(r), boost::end(r)))
{ }
};
+22 -4
View File
@@ -20,6 +20,7 @@
#include <boost/range/concepts.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/optional/optional.hpp>
namespace boost
{
@@ -32,19 +33,36 @@ namespace boost
typedef const Value& result_type;
typedef const Value& first_argument_type;
// Rationale:
// The default constructor is required to allow the transform
// iterator to properly model the iterator concept.
replace_value()
{
}
replace_value(const Value& from, const Value& to)
: m_from(from), m_to(to)
: m_impl(data(from, to))
{
}
const Value& operator()(const Value& x) const
{
return (x == m_from) ? m_to : x;
return (x == m_impl->m_from) ? m_impl->m_to : x;
}
private:
Value m_from;
Value m_to;
struct data
{
data(const Value& from, const Value& to)
: m_from(from)
, m_to(to)
{
}
Value m_from;
Value m_to;
};
boost::optional<data> m_impl;
};
template< class R >
+20 -4
View File
@@ -20,6 +20,7 @@
#include <boost/range/concepts.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/optional/optional.hpp>
namespace boost
{
@@ -32,19 +33,34 @@ namespace boost
typedef const Value& result_type;
typedef const Value& first_argument_type;
// Rationale:
// required to allow the iterator to be default constructible.
replace_value_if()
{
}
replace_value_if(const Pred& pred, const Value& to)
: m_pred(pred), m_to(to)
: m_impl(data(pred, to))
{
}
const Value& operator()(const Value& x) const
{
return m_pred(x) ? m_to : x;
return m_impl->m_pred(x) ? m_impl->m_to : x;
}
private:
Pred m_pred;
Value m_to;
struct data
{
data(const Pred& p, const Value& t)
: m_pred(p), m_to(t)
{
}
Pred m_pred;
Value m_to;
};
boost::optional<data> m_impl;
};
template< class Pred, class R >
+31 -15
View File
@@ -12,6 +12,7 @@
#define BOOST_RANGE_ADAPTOR_TRANSFORMED_HPP
#include <boost/range/adaptor/argument_fwd.hpp>
#include <boost/range/detail/default_constructible_unary_fn.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/range/concepts.hpp>
#include <boost/iterator/transform_iterator.hpp>
@@ -21,31 +22,46 @@ namespace boost
{
namespace range_detail
{
// A type generator to produce the transform_iterator type conditionally
// including a wrapped predicate as appropriate.
template<typename P, typename It>
struct transform_iterator_gen
{
typedef transform_iterator<
typename default_constructible_unary_fn_gen<
P,
typename transform_iterator<P, It>::reference
>::type,
It
> type;
};
template< class F, class R >
struct transformed_range :
public boost::iterator_range<
boost::transform_iterator< F,
BOOST_DEDUCED_TYPENAME range_iterator<R>::type
>
>
typename transform_iterator_gen<
F, typename range_iterator<R>::type>::type>
{
private:
typedef boost::iterator_range<
boost::transform_iterator< F,
BOOST_DEDUCED_TYPENAME range_iterator<R>::type
>
>
base;
typedef typename transform_iterator_gen<
F, typename range_iterator<R>::type>::type transform_iter_t;
typedef boost::iterator_range<transform_iter_t> base;
public:
typedef F transform_fn_type;
typedef typename default_constructible_unary_fn_gen<
F,
typename transform_iterator<
F,
typename range_iterator<R>::type
>::reference
>::type transform_fn_type;
typedef R source_range_type;
transformed_range( F f, R& r )
: base( boost::make_transform_iterator( boost::begin(r), f ),
boost::make_transform_iterator( boost::end(r), f ) )
transformed_range(transform_fn_type f, R& r)
: base(transform_iter_t(boost::begin(r), f),
transform_iter_t(boost::end(r), f))
{
}
};
@@ -15,7 +15,6 @@
#include <boost/range/iterator_range_core.hpp>
#include <boost/range/any_range.hpp>
#include <boost/range/concepts.hpp>
#include <boost/cast.hpp>
namespace boost
{
Executable → Regular
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
-1
View File
@@ -19,7 +19,6 @@
#include <boost/range/reference.hpp>
#include <boost/range/value_type.hpp>
#include <boost/range/iterator_range_core.hpp>
#include <boost/cast.hpp>
namespace boost
{
Executable → Regular
View File
@@ -10,7 +10,6 @@
#ifndef BOOST_RANGE_DETAIL_ANY_ITERATOR_HPP_INCLUDED
#define BOOST_RANGE_DETAIL_ANY_ITERATOR_HPP_INCLUDED
#include <boost/cast.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/not.hpp>
@@ -10,7 +10,7 @@
#ifndef BOOST_RANGE_DETAIL_ANY_ITERATOR_WRAPPER_HPP_INCLUDED
#define BOOST_RANGE_DETAIL_ANY_ITERATOR_WRAPPER_HPP_INCLUDED
#include <boost/cast.hpp>
#include <boost/polymorphic_cast.hpp>
#include <boost/range/config.hpp>
#include <boost/range/detail/any_iterator_interface.hpp>
#include <boost/range/concepts.hpp>
View File
@@ -0,0 +1,64 @@
// Boost.Range library
//
// Copyright Neil Groves 2014. 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_DETAIL_DEFAULT_CONSTRUCTIBLE_UNARY_FN_HPP_INCLUDED
#define BOOST_RANGE_DETAIL_DEFAULT_CONSTRUCTIBLE_UNARY_FN_HPP_INCLUDED
#include <boost/optional/optional.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/has_trivial_constructor.hpp>
namespace boost
{
namespace range_detail
{
template<typename F, typename R>
class default_constructible_unary_fn_wrapper
{
public:
typedef R result_type;
default_constructible_unary_fn_wrapper()
{
}
default_constructible_unary_fn_wrapper(const F& source)
: m_impl(source)
{
}
template<typename Arg>
R operator()(const Arg& arg) const
{
BOOST_ASSERT(m_impl);
return (*m_impl)(arg);
}
template<typename Arg>
R operator()(Arg& arg) const
{
BOOST_ASSERT(m_impl);
return (*m_impl)(arg);
}
private:
boost::optional<F> m_impl;
};
template<typename F, typename R>
struct default_constructible_unary_fn_gen
{
typedef typename boost::mpl::if_<
boost::has_trivial_default_constructor<F>,
F,
default_constructible_unary_fn_wrapper<F,R>
>::type type;
};
} // namespace range_detail
} // namespace boost
#endif // include guard
View File
View File
@@ -15,36 +15,32 @@
#endif
#include <boost/config.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/mpl/has_xxx.hpp>
#ifdef BOOST_NO_PARTIAL_SPECIALIZATION_IMPLICIT_DEFAULT_ARGS
#define BOOST_RANGE_EXTRACT_OPTIONAL_TYPE( a_typedef ) \
template< typename C > \
struct extract_ ## a_typedef \
{ \
typedef BOOST_DEDUCED_TYPENAME C::a_typedef type; \
};
#else
namespace boost {
namespace range_detail {
template< typename T > struct exists { typedef void type; };
}
}
#if !defined(BOOST_MPL_CFG_NO_HAS_XXX)
// Defines extract_some_typedef<T> which exposes T::some_typedef as
// extract_some_typedef<T>::type if T::some_typedef exists. Otherwise
// extract_some_typedef<T> is empty.
#define BOOST_RANGE_EXTRACT_OPTIONAL_TYPE( a_typedef ) \
template< typename C, typename Enable=void > \
struct extract_ ## a_typedef \
{}; \
template< typename C > \
struct extract_ ## a_typedef< C \
, BOOST_DEDUCED_TYPENAME boost::range_detail::exists< BOOST_DEDUCED_TYPENAME C::a_typedef >::type \
> { \
typedef BOOST_DEDUCED_TYPENAME C::a_typedef type; \
#define BOOST_RANGE_EXTRACT_OPTIONAL_TYPE( a_typedef ) \
BOOST_MPL_HAS_XXX_TRAIT_DEF(a_typedef) \
template< typename C, bool B = BOOST_PP_CAT(has_, a_typedef)<C>::value > \
struct BOOST_PP_CAT(extract_, a_typedef) \
{}; \
template< typename C > \
struct BOOST_PP_CAT(extract_, a_typedef)< C, true > \
{ \
typedef BOOST_DEDUCED_TYPENAME C::a_typedef type; \
};
#else
#define BOOST_RANGE_EXTRACT_OPTIONAL_TYPE( a_typedef ) \
template< typename C > \
struct BOOST_PP_CAT(extract_, a_typedef) \
{ \
typedef BOOST_DEDUCED_TYPENAME C::a_typedef type; \
};
#endif
View File
View File
View File
View File
View File
+1
View File
@@ -57,6 +57,7 @@ test-suite range :
[ compile-fail compile_fail/adaptor/uniqued_concept3.cpp ]
[ compile-fail compile_fail/adaptor/uniqued_concept4.cpp ]
[ range-test adaptor_test/adjacent_filtered ]
[ range-test adaptor_test/chained ]
[ range-test adaptor_test/copied ]
[ range-test adaptor_test/filtered ]
[ range-test adaptor_test/indexed ]
+117
View File
@@ -0,0 +1,117 @@
// Boost.Range library
//
// Copyright Neil Groves 2014. 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/
//
// Credits:
// Jurgen Hunold provided a test case that demonstrated that the range adaptors
// were producing iterators that were not default constructible. This became
// symptomatic after enabling concept checking assertions. This test is a
// lightly modified version of his supplied code to ensure that his use case
// never breaks again. (hopefully!)
//
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/bind.hpp>
#include <boost/test/test_tools.hpp>
#include <boost/test/unit_test.hpp>
#include <vector>
#include <set>
namespace boost_range_test
{
namespace
{
class foo
{
public:
static foo from_string(const std::string& source)
{
foo f;
f.m_valid = true;
f.m_value = 0u;
for (std::string::const_iterator it = source.begin();
it != source.end(); ++it)
{
f.m_value += *it;
if ((*it < 'a') || (*it > 'z'))
f.m_valid = false;
}
return f;
}
bool is_valid() const
{
return m_valid;
}
bool operator<(const foo& other) const
{
return m_value < other.m_value;
}
bool operator==(const foo& other) const
{
return m_value == other.m_value && m_valid == other.m_valid;
}
bool operator!=(const foo& other) const
{
return !operator==(other);
}
friend inline std::ostream& operator<<(std::ostream& out, const foo& obj)
{
out << "{value=" << obj.m_value
<< ", valid=" << std::boolalpha << obj.m_valid << "}\n";
return out;
}
private:
boost::uint64_t m_value;
bool m_valid;
};
void chained_adaptors_test()
{
std::vector<std::string> sep;
sep.push_back("AB");
sep.push_back("ab");
sep.push_back("aghj");
std::set<foo> foos;
boost::copy(sep
| boost::adaptors::transformed(boost::bind(&foo::from_string, _1))
| boost::adaptors::filtered(boost::bind(&foo::is_valid, _1)),
std::inserter(foos, foos.end()));
std::vector<foo> reference;
reference.push_back(foo::from_string("ab"));
reference.push_back(foo::from_string("aghj"));
BOOST_CHECK_EQUAL_COLLECTIONS(
reference.begin(), reference.end(),
foos.begin(), foos.end());
}
} // anonymous namespace
} // namespace boost_range_test
boost::unit_test::test_suite*
init_unit_test_suite(int argc, char* argv[])
{
boost::unit_test::test_suite* test
= BOOST_TEST_SUITE( "RangeTestSuite.adaptor.chained adaptors" );
test->add(BOOST_TEST_CASE( boost_range_test::chained_adaptors_test));
return test;
}
View File
+46 -30
View File
@@ -8,6 +8,10 @@
//
// For more information, see http://www.boost.org/libs/range/
//
// Credits:
// awulkiew highlighted that this test was not successfully testing the
// algorithm.
//
#include <boost/range/algorithm/copy_backward.hpp>
#include <boost/test/test_tools.hpp>
@@ -17,52 +21,64 @@
#include <boost/range/iterator.hpp>
#include <algorithm>
#include <list>
#include <set>
#include <vector>
namespace boost
namespace boost_range_test
{
namespace
{
template< class Container >
void test_copy_backward_impl()
{
Container source;
typedef BOOST_DEDUCED_TYPENAME Container::value_type value_t;
template<typename Container>
void test_copy_backward_impl(std::size_t n)
{
Container source;
typedef typename Container::value_type value_t;
for (std::size_t i = 0; i < n; ++i)
source.push_back(static_cast<value_t>(i));
std::vector<value_t> target;
target.resize(source.size());
std::vector<value_t> target(n);
typedef BOOST_DEDUCED_TYPENAME range_iterator< std::vector<value_t> >::type iterator_t;
iterator_t it = boost::copy_backward(source, target.begin());
typedef typename boost::range_iterator<
std::vector<value_t>
>::type iterator_t;
BOOST_CHECK( it == target.end() );
BOOST_CHECK_EQUAL_COLLECTIONS( target.begin(), target.end(),
source.rbegin(), source.rend() );
BOOST_CHECK( it == boost::copy_backward(boost::make_iterator_range(source), target.begin()) );
BOOST_CHECK_EQUAL_COLLECTIONS( target.begin(), target.end(),
source.rbegin(), source.rend() );
}
iterator_t it = boost::copy_backward(source, target.end());
void test_copy_backward()
{
test_copy_backward_impl< std::vector<int> >();
test_copy_backward_impl< std::list<int> >();
test_copy_backward_impl< std::set<int> >();
test_copy_backward_impl< std::multiset<int> >();
}
}
BOOST_CHECK(it == target.begin());
BOOST_CHECK_EQUAL_COLLECTIONS(target.begin(), target.end(),
source.begin(), source.end());
BOOST_CHECK(it == boost::copy_backward(
boost::make_iterator_range(source), target.end()));
BOOST_CHECK_EQUAL_COLLECTIONS(target.begin(), target.end(),
source.begin(), source.end());
}
template<typename Container>
void test_copy_backward_impl()
{
test_copy_backward_impl<Container>(0u);
test_copy_backward_impl<Container>(1u);
test_copy_backward_impl<Container>(100u);
}
void test_copy_backward()
{
test_copy_backward_impl<std::vector<int> >();
test_copy_backward_impl<std::list<int> >();
}
} // anonymous namespace
} // namespace boost_range_test
boost::unit_test::test_suite*
init_unit_test_suite(int argc, char* argv[])
init_unit_test_suite(int, char*[])
{
boost::unit_test::test_suite* test
= BOOST_TEST_SUITE( "RangeTestSuite.algorithm.copy_backward" );
= BOOST_TEST_SUITE("RangeTestSuite.algorithm.copy_backward");
test->add( BOOST_TEST_CASE( &boost::test_copy_backward ) );
test->add(BOOST_TEST_CASE(&boost_range_test::test_copy_backward));
return test;
}
Executable → Regular
View File