1 // Boost.Range library
2 //
3 //  Copyright Neil Groves 2007. Use, modification and
4 //  distribution is subject to the Boost Software License, Version
5 //  1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 //  http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // For more information, see http://www.boost.org/libs/range/
9 //
10 
11 #ifndef BOOST_RANGE_ADAPTOR_REPLACED_IF_IMPL_HPP_INCLUDED
12 #define BOOST_RANGE_ADAPTOR_REPLACED_IF_IMPL_HPP_INCLUDED
13 
14 #include <boost/config.hpp>
15 #include <boost/range/adaptor/argument_fwd.hpp>
16 #include <boost/range/iterator_range.hpp>
17 #include <boost/range/begin.hpp>
18 #include <boost/range/end.hpp>
19 #include <boost/range/value_type.hpp>
20 #include <boost/range/concepts.hpp>
21 #include <boost/iterator/iterator_adaptor.hpp>
22 #include <boost/iterator/transform_iterator.hpp>
23 #include <boost/optional/optional.hpp>
24 
25 namespace boost
26 {
27     namespace range_detail
28     {
29         template< class Pred, class Value >
30         class replace_value_if
31         {
32         public:
33             typedef const Value& result_type;
34             typedef const Value& first_argument_type;
35 
36             // Rationale:
37             // required to allow the iterator to be default constructible.
replace_value_if()38             replace_value_if()
39             {
40             }
41 
replace_value_if(const Pred & pred,const Value & to)42             replace_value_if(const Pred& pred, const Value& to)
43                 : m_impl(data(pred, to))
44             {
45             }
46 
operator ()(const Value & x) const47             const Value& operator()(const Value& x) const
48             {
49                 return m_impl->m_pred(x) ? m_impl->m_to : x;
50             }
51 
52         private:
53             struct data
54             {
databoost::range_detail::replace_value_if::data55                 data(const Pred& p, const Value& t)
56                     : m_pred(p), m_to(t)
57                 {
58                 }
59 
60                 Pred  m_pred;
61                 Value m_to;
62             };
63             boost::optional<data> m_impl;
64         };
65 
66         template< class Pred, class R >
67         class replaced_if_range :
68             public boost::iterator_range<
69                 boost::transform_iterator<
70                     replace_value_if< Pred, BOOST_DEDUCED_TYPENAME range_value<R>::type >,
71                     BOOST_DEDUCED_TYPENAME range_iterator<R>::type > >
72         {
73         private:
74             typedef replace_value_if< Pred, BOOST_DEDUCED_TYPENAME range_value<R>::type > Fn;
75 
76             typedef boost::iterator_range<
77                 boost::transform_iterator<
78                     replace_value_if< Pred, BOOST_DEDUCED_TYPENAME range_value<R>::type >,
79                     BOOST_DEDUCED_TYPENAME range_iterator<R>::type > > base_t;
80 
81         public:
82             typedef BOOST_DEDUCED_TYPENAME range_value<R>::type value_type;
83 
replaced_if_range(R & r,const Pred & pred,value_type to)84             replaced_if_range( R& r, const Pred& pred, value_type to )
85                 : base_t( make_transform_iterator( boost::begin(r), Fn(pred, to) ),
86                           make_transform_iterator( boost::end(r), Fn(pred, to) ) )
87             { }
88         };
89 
90         template< class Pred, class T >
91         class replace_if_holder
92         {
93         public:
replace_if_holder(const Pred & pred,const T & to)94             replace_if_holder( const Pred& pred, const T& to )
95                 : m_pred(pred), m_to(to)
96             { }
97 
pred() const98             const Pred& pred() const { return m_pred; }
to() const99             const T& to() const { return m_to; }
100 
101         private:
102             Pred m_pred;
103             T m_to;
104         };
105 
106         template< class Pred, class SinglePassRange >
107         inline replaced_if_range<Pred, SinglePassRange>
operator |(SinglePassRange & r,const replace_if_holder<Pred,BOOST_DEDUCED_TYPENAME range_value<SinglePassRange>::type> & f)108         operator|(
109             SinglePassRange& r,
110             const replace_if_holder<
111                 Pred,
112                 BOOST_DEDUCED_TYPENAME range_value<SinglePassRange>::type>& f)
113         {
114             BOOST_RANGE_CONCEPT_ASSERT((
115                 SinglePassRangeConcept<SinglePassRange>));
116 
117             return replaced_if_range<Pred, SinglePassRange>(
118                 r, f.pred(), f.to());
119         }
120 
121         template< class Pred, class SinglePassRange >
122         inline replaced_if_range<Pred, const SinglePassRange>
operator |(const SinglePassRange & r,const replace_if_holder<Pred,BOOST_DEDUCED_TYPENAME range_value<SinglePassRange>::type> & f)123         operator|(
124             const SinglePassRange& r,
125             const replace_if_holder<
126                 Pred,
127                 BOOST_DEDUCED_TYPENAME range_value<SinglePassRange>::type>& f)
128         {
129             BOOST_RANGE_CONCEPT_ASSERT((
130                 SinglePassRangeConcept<const SinglePassRange>));
131 
132             return replaced_if_range<Pred, const SinglePassRange>(
133                 r, f.pred(), f.to());
134         }
135     } // 'range_detail'
136 
137     using range_detail::replaced_if_range;
138 
139     namespace adaptors
140     {
141         namespace
142         {
143             const range_detail::forwarder2TU<range_detail::replace_if_holder>
144                 replaced_if =
145                     range_detail::forwarder2TU<range_detail::replace_if_holder>();
146         }
147 
148         template<class Pred, class SinglePassRange>
149         inline replaced_if_range<Pred, SinglePassRange>
replace_if(SinglePassRange & rng,Pred pred,BOOST_DEDUCED_TYPENAME range_value<SinglePassRange>::type to)150         replace_if(SinglePassRange& rng, Pred pred,
151                    BOOST_DEDUCED_TYPENAME range_value<SinglePassRange>::type to)
152         {
153             BOOST_RANGE_CONCEPT_ASSERT((
154                 SinglePassRangeConcept<SinglePassRange>));
155 
156             return range_detail::replaced_if_range<Pred, SinglePassRange>(
157                 rng, pred, to);
158         }
159 
160         template<class Pred, class SinglePassRange>
161         inline replaced_if_range<Pred, const SinglePassRange>
replace_if(const SinglePassRange & rng,Pred pred,BOOST_DEDUCED_TYPENAME range_value<const SinglePassRange>::type to)162         replace_if(
163             const SinglePassRange& rng,
164             Pred pred,
165             BOOST_DEDUCED_TYPENAME range_value<const SinglePassRange>::type to)
166         {
167             BOOST_RANGE_CONCEPT_ASSERT((
168                 SinglePassRangeConcept<const SinglePassRange>));
169 
170             return range_detail::replaced_if_range<Pred, const SinglePassRange>(
171                 rng, pred, to);
172         }
173     } // 'adaptors'
174 
175 } // 'boost'
176 
177 #endif // include guard
178