• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 ///////////////////////////////////////////////////////////////////////////////
2 /// \file regex_iterator.hpp
3 /// Contains the definition of the regex_iterator type, an STL-compatible iterator
4 /// for stepping through all the matches in a sequence.
5 //
6 //  Copyright 2008 Eric Niebler. Distributed under the Boost
7 //  Software License, Version 1.0. (See accompanying file
8 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 
10 #ifndef BOOST_XPRESSIVE_REGEX_ITERATOR_HPP_EAN_10_04_2005
11 #define BOOST_XPRESSIVE_REGEX_ITERATOR_HPP_EAN_10_04_2005
12 
13 // MS compatible compilers support #pragma once
14 #if defined(_MSC_VER)
15 # pragma once
16 #endif
17 
18 #include <boost/noncopyable.hpp>
19 #include <boost/intrusive_ptr.hpp>
20 #include <boost/iterator/iterator_traits.hpp>
21 #include <boost/xpressive/detail/detail_fwd.hpp>
22 #include <boost/xpressive/detail/core/access.hpp>
23 #include <boost/xpressive/detail/utility/counted_base.hpp>
24 
25 namespace boost { namespace xpressive { namespace detail
26 {
27 
28 //////////////////////////////////////////////////////////////////////////
29 // regex_iterator_impl
30 //
31 template<typename BidiIter>
32 struct regex_iterator_impl
33   : counted_base<regex_iterator_impl<BidiIter> >
34 {
35     typedef detail::core_access<BidiIter> access;
36 
regex_iterator_implboost::xpressive::detail::regex_iterator_impl37     regex_iterator_impl
38     (
39         BidiIter begin
40       , BidiIter cur
41       , BidiIter end
42       , BidiIter next_search
43       , basic_regex<BidiIter> const &rex
44       , regex_constants::match_flag_type flags
45       , bool not_null = false
46     )
47       : rex_(rex)
48       , what_()
49       , state_(begin, end, what_, *access::get_regex_impl(rex_), flags)
50       , flags_(flags)
51       , not_null_(not_null)
52     {
53         this->state_.cur_ = cur;
54         this->state_.next_search_ = next_search;
55     }
56 
nextboost::xpressive::detail::regex_iterator_impl57     bool next()
58     {
59         this->state_.reset(this->what_, *access::get_regex_impl(this->rex_));
60         if(!regex_search_impl(this->state_, this->rex_, this->not_null_))
61         {
62             return false;
63         }
64 
65         // Report position() correctly by setting the base different from prefix().first
66         access::set_base(this->what_, this->state_.begin_);
67 
68         this->state_.cur_ = this->state_.next_search_ = this->what_[0].second;
69         this->not_null_ = (0 == this->what_.length());
70 
71         return true;
72     }
73 
equal_toboost::xpressive::detail::regex_iterator_impl74     bool equal_to(regex_iterator_impl<BidiIter> const &that) const
75     {
76         return this->rex_.regex_id()    == that.rex_.regex_id()
77             && this->state_.begin_      == that.state_.begin_
78             && this->state_.cur_        == that.state_.cur_
79             && this->state_.end_        == that.state_.end_
80             && this->flags_             == that.flags_
81             ;
82     }
83 
84     basic_regex<BidiIter> rex_;
85     match_results<BidiIter> what_;
86     match_state<BidiIter> state_;
87     regex_constants::match_flag_type const flags_;
88     bool not_null_;
89 };
90 
91 } // namespace detail
92 
93 //////////////////////////////////////////////////////////////////////////
94 // regex_iterator
95 //
96 template<typename BidiIter>
97 struct regex_iterator
98 {
99     typedef basic_regex<BidiIter> regex_type;
100     typedef match_results<BidiIter> value_type;
101     typedef typename iterator_difference<BidiIter>::type difference_type;
102     typedef value_type const *pointer;
103     typedef value_type const &reference;
104     typedef std::forward_iterator_tag iterator_category;
105 
106     /// INTERNAL ONLY
107     typedef detail::regex_iterator_impl<BidiIter> impl_type_;
108 
regex_iteratorboost::xpressive::regex_iterator109     regex_iterator()
110       : impl_()
111     {
112     }
113 
regex_iteratorboost::xpressive::regex_iterator114     regex_iterator
115     (
116         BidiIter begin
117       , BidiIter end
118       , basic_regex<BidiIter> const &rex
119       , regex_constants::match_flag_type flags = regex_constants::match_default
120     )
121       : impl_()
122     {
123         if(0 != rex.regex_id()) // Empty regexes are guaranteed to match nothing
124         {
125           this->impl_ = new impl_type_(begin, begin, end, begin, rex, flags);
126           this->next_();
127         }
128     }
129 
130     template<typename LetExpr>
regex_iteratorboost::xpressive::regex_iterator131     regex_iterator
132     (
133         BidiIter begin
134       , BidiIter end
135       , basic_regex<BidiIter> const &rex
136       , detail::let_<LetExpr> const &args
137       , regex_constants::match_flag_type flags = regex_constants::match_default
138     )
139       : impl_()
140     {
141         if(0 != rex.regex_id()) // Empty regexes are guaranteed to match nothing
142         {
143           this->impl_ = new impl_type_(begin, begin, end, begin, rex, flags);
144           detail::bind_args(args, this->impl_->what_);
145           this->next_();
146         }
147     }
148 
regex_iteratorboost::xpressive::regex_iterator149     regex_iterator(regex_iterator<BidiIter> const &that)
150       : impl_(that.impl_) // COW
151     {
152     }
153 
operator =boost::xpressive::regex_iterator154     regex_iterator<BidiIter> &operator =(regex_iterator<BidiIter> const &that)
155     {
156         this->impl_ = that.impl_; // COW
157         return *this;
158     }
159 
operator ==(regex_iterator<BidiIter> const & left,regex_iterator<BidiIter> const & right)160     friend bool operator ==(regex_iterator<BidiIter> const &left, regex_iterator<BidiIter> const &right)
161     {
162         if(!left.impl_ || !right.impl_)
163         {
164             return !left.impl_ && !right.impl_;
165         }
166 
167         return left.impl_->equal_to(*right.impl_);
168     }
169 
operator !=(regex_iterator<BidiIter> const & left,regex_iterator<BidiIter> const & right)170     friend bool operator !=(regex_iterator<BidiIter> const &left, regex_iterator<BidiIter> const &right)
171     {
172         return !(left == right);
173     }
174 
operator *boost::xpressive::regex_iterator175     value_type const &operator *() const
176     {
177         return this->impl_->what_;
178     }
179 
operator ->boost::xpressive::regex_iterator180     value_type const *operator ->() const
181     {
182         return &this->impl_->what_;
183     }
184 
185     /// If what.prefix().first != what[0].second and if the element match_prev_avail is not set in
186     /// flags then sets it. Then behaves as if by calling regex_search(what[0].second, end, what, *pre, flags),
187     /// with the following variation: in the event that the previous match found was of zero length
188     /// (what[0].length() == 0) then attempts to find a non-zero length match starting at what[0].second,
189     /// only if that fails and provided what[0].second != suffix().second does it look for a (possibly
190     /// zero length) match starting from what[0].second + 1.  If no further match is found then sets
191     /// *this equal to the end of sequence iterator.
192     /// \post (*this)-\>size() == pre-\>mark_count() + 1
193     /// \post (*this)-\>empty() == false
194     /// \post (*this)-\>prefix().first == An iterator denoting the end point of the previous match found
195     /// \post (*this)-\>prefix().last == (**this)[0].first
196     /// \post (*this)-\>prefix().matched == (*this)-\>prefix().first != (*this)-\>prefix().second
197     /// \post (*this)-\>suffix().first == (**this)[0].second
198     /// \post (*this)-\>suffix().last == end
199     /// \post (*this)-\>suffix().matched == (*this)-\>suffix().first != (*this)-\>suffix().second
200     /// \post (**this)[0].first == The starting iterator for this match.
201     /// \post (**this)[0].second == The ending iterator for this match.
202     /// \post (**this)[0].matched == true if a full match was found, and false if it was a partial match (found as a result of the match_partial flag being set).
203     /// \post (**this)[n].first == For all integers n \< (*this)-\>size(), the start of the sequence that matched sub-expression n. Alternatively, if sub-expression n did not participate in the match, then end.
204     /// \post (**this)[n].second == For all integers n \< (*this)-\>size(), the end of the sequence that matched sub-expression n. Alternatively, if sub-expression n did not participate in the match, then end.
205     /// \post (**this)[n].matched == For all integers n \< (*this)-\>size(), true if sub-expression n participated in the match, false otherwise.
206     /// \post (*this)-\>position() == The distance from the start of the original sequence being iterated, to the start of this match.
operator ++boost::xpressive::regex_iterator207     regex_iterator<BidiIter> &operator ++()
208     {
209         this->fork_(); // un-share the implementation
210         this->next_();
211         return *this;
212     }
213 
operator ++boost::xpressive::regex_iterator214     regex_iterator<BidiIter> operator ++(int)
215     {
216         regex_iterator<BidiIter> tmp(*this);
217         ++*this;
218         return tmp;
219     }
220 
221 private:
222 
223     /// INTERNAL ONLY
fork_boost::xpressive::regex_iterator224     void fork_()
225     {
226         if(1 != this->impl_->use_count())
227         {
228             // This is OK, the use_count is > 1
229             impl_type_ *that = this->impl_.get();
230             this->impl_ = new impl_type_
231             (
232                 that->state_.begin_
233               , that->state_.cur_
234               , that->state_.end_
235               , that->state_.next_search_
236               , that->rex_
237               , that->flags_
238               , that->not_null_
239             );
240             detail::core_access<BidiIter>::get_action_args(this->impl_->what_)
241                 = detail::core_access<BidiIter>::get_action_args(that->what_);
242         }
243     }
244 
245     /// INTERNAL ONLY
next_boost::xpressive::regex_iterator246     void next_()
247     {
248         BOOST_ASSERT(this->impl_ && 1 == this->impl_->use_count());
249         if(!this->impl_->next())
250         {
251             this->impl_ = 0;
252         }
253     }
254 
255     intrusive_ptr<impl_type_> impl_;
256 };
257 
258 }} // namespace boost::xpressive
259 
260 #endif
261