Skip to content

Fixing non-reference base_t::reference case with replaced_if adaptor #108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 26 additions & 13 deletions include/boost/range/adaptor/replaced_if.hpp
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -16,49 +16,62 @@
#include <boost/range/iterator_range.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
#include <boost/range/reference.hpp>
#include <boost/range/concepts.hpp>
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/optional/optional.hpp>
#include <boost/move/utility_core.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/remove_const.hpp>
#include <boost/type_traits/is_reference.hpp>
#include <boost/type_traits/conditional.hpp>

namespace boost
{
namespace range_detail
{
template< class Pred, class Value >
template< class Pred, class Reference >
class replace_value_if
{
public:
typedef const Value& result_type;
typedef const Value& first_argument_type;
typedef BOOST_DEDUCED_TYPENAME boost::conditional<boost::is_reference<Reference>::value,
const BOOST_DEDUCED_TYPENAME boost::remove_reference<Reference>::type&,
Reference>::type result_type;
typedef Reference 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)
replace_value_if(const Pred& pred, const BOOST_DEDUCED_TYPENAME boost::remove_reference<Reference>::type& to)
: m_impl(data(pred, to))
{
}

const Value& operator()(const Value& x) const
result_type operator()(Reference x) const
{
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
return m_impl->m_pred(x) ? m_impl->m_to : x;
#else
return m_impl->m_pred(x) ? m_impl->m_to : boost::forward<Reference>(x);
#endif
}

private:


struct data
{
data(const Pred& p, const Value& t)
data(const Pred& p, const BOOST_DEDUCED_TYPENAME boost::remove_reference<Reference>::type& t)
: m_pred(p), m_to(t)
{
}

Pred m_pred;
Value m_to;
BOOST_DEDUCED_TYPENAME boost::remove_const<BOOST_DEDUCED_TYPENAME boost::remove_reference<Reference>::type>::type m_to;
};
boost::optional<data> m_impl;
};
Expand All @@ -67,21 +80,21 @@ namespace boost
class replaced_if_range :
public boost::iterator_range<
boost::transform_iterator<
replace_value_if< Pred, BOOST_DEDUCED_TYPENAME range_value<R>::type >,
replace_value_if< Pred, BOOST_DEDUCED_TYPENAME range_reference<R>::type >,
BOOST_DEDUCED_TYPENAME range_iterator<R>::type > >
{
private:
typedef replace_value_if< Pred, BOOST_DEDUCED_TYPENAME range_value<R>::type > Fn;
typedef replace_value_if< Pred, BOOST_DEDUCED_TYPENAME range_reference<R>::type > Fn;

typedef boost::iterator_range<
boost::transform_iterator<
replace_value_if< Pred, BOOST_DEDUCED_TYPENAME range_value<R>::type >,
replace_value_if< Pred, BOOST_DEDUCED_TYPENAME range_reference<R>::type >,
BOOST_DEDUCED_TYPENAME range_iterator<R>::type > > base_t;

public:
typedef BOOST_DEDUCED_TYPENAME range_value<R>::type value_type;
typedef BOOST_DEDUCED_TYPENAME range_reference<R>::type reference_type;

replaced_if_range( R& r, const Pred& pred, value_type to )
replaced_if_range( R& r, const Pred& pred, const BOOST_DEDUCED_TYPENAME boost::remove_reference<reference_type>::type& to )
: base_t( make_transform_iterator( boost::begin(r), Fn(pred, to) ),
make_transform_iterator( boost::end(r), Fn(pred, to) ) )
{ }
Expand Down
37 changes: 37 additions & 0 deletions test/adaptor_test/replaced_if.cpp
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
// For more information, see http://www.boost.org/libs/range/
//
#include <boost/range/adaptor/replaced_if.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/iterator_range.hpp>

#include <boost/test/test_tools.hpp>
#include <boost/test/unit_test.hpp>
Expand All @@ -30,6 +32,13 @@ namespace boost
bool operator()(int x) const { return x == 1; }
};

struct minus_one
{
typedef int result_type;
typedef int argument_type;
int operator()(int x) const {return x - 1; }
};

template< class Container >
void replaced_if_test_impl( Container& c )
{
Expand Down Expand Up @@ -81,6 +90,33 @@ namespace boost
replaced_if_test_impl< std::set< int > >();
replaced_if_test_impl< std::multiset< int > >();
}

void replaced_if_combined_with_transformed_test()
{
using namespace boost::adaptors;
using namespace boost::assign;

minus_one unary_fn;
if_value_is_one pred;

std::vector<int> input;

input += 4,3,2,1;

const int replacement_value = 7;

std::vector<int> reference;

std::vector<int> temp;
boost::push_back(temp, input | transformed(unary_fn));
boost::push_back(reference, temp | replaced_if(pred, replacement_value));

std::vector<int> test_result = boost::copy_range< std::vector<int> >(input | transformed(unary_fn)
| replaced_if(pred, replacement_value));

BOOST_CHECK_EQUAL_COLLECTIONS( reference.begin(), reference.end(),
test_result.begin(), test_result.end() );
}
}
}

Expand All @@ -91,6 +127,7 @@ init_unit_test_suite(int argc, char* argv[])
= BOOST_TEST_SUITE( "RangeTestSuite.adaptor.replaced_if" );

test->add( BOOST_TEST_CASE( &boost::replaced_if_test ) );
test->add( BOOST_TEST_CASE( &boost::replaced_if_combined_with_transformed_test ) );

return test;
}