1 /*
2  *
3  * Copyright (c) 1998-2002
4  * John Maddock
5  *
6  * Use, modification and distribution are subject to the
7  * Boost 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  */
11 
12  /*
13   *   LOCATION:    see http://www.boost.org for most recent version.
14   *   FILE         match_results.cpp
15   *   VERSION      see <boost/version.hpp>
16   *   DESCRIPTION: Declares template class match_results.
17   */
18 
19 #ifndef BOOST_REGEX_V4_MATCH_RESULTS_HPP
20 #define BOOST_REGEX_V4_MATCH_RESULTS_HPP
21 
22 #ifdef BOOST_HAS_ABI_HEADERS
23 #  include BOOST_ABI_PREFIX
24 #endif
25 
26 namespace boost{
27 #ifdef BOOST_MSVC
28 #pragma warning(push)
29 #pragma warning(disable : 4251 4231 4660)
30 #endif
31 
32 template <class BidiIterator, class Allocator>
33 class match_results
34 {
35 private:
36 #ifndef BOOST_NO_STD_ALLOCATOR
37    typedef          std::vector<sub_match<BidiIterator>, Allocator> vector_type;
38 #else
39    typedef          std::vector<sub_match<BidiIterator> >           vector_type;
40 #endif
41 public:
42    typedef          sub_match<BidiIterator>                         value_type;
43 #if  !defined(BOOST_NO_STD_ALLOCATOR) && !(defined(BOOST_MSVC) && defined(_STLPORT_VERSION))
44    typedef typename Allocator::const_reference                              const_reference;
45 #else
46    typedef          const value_type&                                       const_reference;
47 #endif
48    typedef          const_reference                                         reference;
49    typedef typename vector_type::const_iterator                             const_iterator;
50    typedef          const_iterator                                          iterator;
51    typedef typename re_detail::regex_iterator_traits<
52                                     BidiIterator>::difference_type          difference_type;
53    typedef typename Allocator::size_type                                    size_type;
54    typedef          Allocator                                               allocator_type;
55    typedef typename re_detail::regex_iterator_traits<
56                                     BidiIterator>::value_type               char_type;
57    typedef          std::basic_string<char_type>                            string_type;
58 
59    // construct/copy/destroy:
match_results(const Allocator & a=Allocator ())60    explicit match_results(const Allocator& a = Allocator())
61 #ifndef BOOST_NO_STD_ALLOCATOR
62       : m_subs(a), m_base() {}
63 #else
64       : m_subs(), m_base() { (void)a; }
65 #endif
match_results(const match_results & m)66    match_results(const match_results& m)
67       : m_subs(m.m_subs), m_base(m.m_base) {}
operator =(const match_results & m)68    match_results& operator=(const match_results& m)
69    {
70       m_subs = m.m_subs;
71       m_base = m.m_base;
72       return *this;
73    }
~match_results()74    ~match_results(){}
75 
76    // size:
size() const77    size_type size() const
78    { return empty() ? 0 : m_subs.size() - 2; }
max_size() const79    size_type max_size() const
80    { return m_subs.max_size(); }
empty() const81    bool empty() const
82    { return m_subs.size() < 2; }
83    // element access:
length(int sub=0) const84    difference_type length(int sub = 0) const
85    {
86       sub += 2;
87       if((sub < (int)m_subs.size()) && (sub > 0))
88          return m_subs[sub].length();
89       return 0;
90    }
position(unsigned int sub=0) const91    difference_type position(unsigned int sub = 0) const
92    {
93       sub += 2;
94       if(sub < m_subs.size())
95       {
96          const sub_match<BidiIterator>& s = m_subs[sub];
97          if(s.matched)
98          {
99             return ::boost::re_detail::distance((BidiIterator)(m_base), (BidiIterator)(s.first));
100          }
101       }
102       return ~static_cast<difference_type>(0);
103    }
str(int sub=0) const104    string_type str(int sub = 0) const
105    {
106       sub += 2;
107       string_type result;
108       if(sub < (int)m_subs.size() && (sub > 0))
109       {
110          const sub_match<BidiIterator>& s = m_subs[sub];
111          if(s.matched)
112          {
113             result = s.str();
114          }
115       }
116       return result;
117    }
operator [](int sub) const118    const_reference operator[](int sub) const
119    {
120       sub += 2;
121       if(sub < (int)m_subs.size() && (sub >= 0))
122       {
123          return m_subs[sub];
124       }
125       return m_null;
126    }
127 
prefix() const128    const_reference prefix() const
129    {
130       return (*this)[-1];
131    }
132 
suffix() const133    const_reference suffix() const
134    {
135       return (*this)[-2];
136    }
begin() const137    const_iterator begin() const
138    {
139       return (m_subs.size() > 2) ? (m_subs.begin() + 2) : m_subs.end();
140    }
end() const141    const_iterator end() const
142    {
143       return m_subs.end();
144    }
145    // format:
146    template <class OutputIterator>
format(OutputIterator out,const string_type & fmt,match_flag_type flags=format_default) const147    OutputIterator format(OutputIterator out,
148                          const string_type& fmt,
149                          match_flag_type flags = format_default) const
150    {
151       re_detail::trivial_format_traits<char_type> traits;
152       return re_detail::regex_format_imp(out, *this, fmt.data(), fmt.data() + fmt.size(), flags, traits);
153    }
format(const string_type & fmt,match_flag_type flags=format_default) const154    string_type format(const string_type& fmt,
155                       match_flag_type flags = format_default) const
156    {
157       string_type result;
158       re_detail::string_out_iterator<string_type> i(result);
159       re_detail::trivial_format_traits<char_type> traits;
160       re_detail::regex_format_imp(i, *this, fmt.data(), fmt.data() + fmt.size(), flags, traits);
161       return result;
162    }
163    // format with locale:
164    template <class OutputIterator, class RegexT>
165    OutputIterator format(OutputIterator out,
166                          const string_type& fmt,
167                          match_flag_type flags,
168                          const RegexT& re) const
169    {
170       return ::boost::re_detail::regex_format_imp(out, *this, fmt.data(), fmt.data() + fmt.size(), flags, re.get_traits());
171    }
172    template <class RegexT>
format(const string_type & fmt,match_flag_type flags,const RegexT & re) const173    string_type format(const string_type& fmt,
174                       match_flag_type flags,
175                       const RegexT& re) const
176    {
177       string_type result;
178       re_detail::string_out_iterator<string_type> i(result);
179       ::boost::re_detail::regex_format_imp(i, *this, fmt.data(), fmt.data() + fmt.size(), flags, re.get_traits());
180       return result;
181    }
182 
get_allocator() const183    allocator_type get_allocator() const
184    {
185 #ifndef BOOST_NO_STD_ALLOCATOR
186       return m_subs.get_allocator();
187 #else
188      return allocator_type();
189 #endif
190    }
swap(match_results & that)191    void swap(match_results& that)
192    {
193       std::swap(m_subs, that.m_subs);
194       std::swap(m_base, that.m_base);
195    }
operator ==(const match_results & that) const196    bool operator==(const match_results& that)const
197    {
198       return (m_subs == that.m_subs) && (m_base == that.m_base);
199    }
operator !=(const match_results & that) const200    bool operator!=(const match_results& that)const
201    { return !(*this == that); }
202 
203 #ifdef BOOST_REGEX_MATCH_EXTRA
204    typedef typename sub_match<BidiIterator>::capture_sequence_type capture_sequence_type;
205 
captures(int i) const206    const capture_sequence_type& captures(int i)const
207    {
208       return (*this)[i].captures();
209    }
210 #endif
211 
212    //
213    // private access functions:
set_second(BidiIterator i)214    void BOOST_REGEX_CALL set_second(BidiIterator i)
215    {
216       BOOST_ASSERT(m_subs.size() > 2);
217       m_subs[2].second = i;
218       m_subs[2].matched = true;
219       m_subs[0].first = i;
220       m_subs[0].matched = (m_subs[0].first != m_subs[0].second);
221       m_null.first = i;
222       m_null.second = i;
223       m_null.matched = false;
224    }
225 
set_second(BidiIterator i,size_type pos,bool m=true)226    void BOOST_REGEX_CALL set_second(BidiIterator i, size_type pos, bool m = true)
227    {
228       pos += 2;
229       BOOST_ASSERT(m_subs.size() > pos);
230       m_subs[pos].second = i;
231       m_subs[pos].matched = m;
232       if(pos == 2)
233       {
234          m_subs[0].first = i;
235          m_subs[0].matched = (m_subs[0].first != m_subs[0].second);
236          m_null.first = i;
237          m_null.second = i;
238          m_null.matched = false;
239       }
240    }
set_size(size_type n,BidiIterator i,BidiIterator j)241    void BOOST_REGEX_CALL set_size(size_type n, BidiIterator i, BidiIterator j)
242    {
243       value_type v(j);
244       size_type len = m_subs.size();
245       if(len > n + 2)
246       {
247          m_subs.erase(m_subs.begin()+n+2, m_subs.end());
248          std::fill(m_subs.begin(), m_subs.end(), v);
249       }
250       else
251       {
252          std::fill(m_subs.begin(), m_subs.end(), v);
253          if(n+2 != len)
254             m_subs.insert(m_subs.end(), n+2-len, v);
255       }
256       m_subs[1].first = i;
257    }
set_base(BidiIterator pos)258    void BOOST_REGEX_CALL set_base(BidiIterator pos)
259    {
260       m_base = pos;
261    }
base() const262    BidiIterator base()const
263    {
264       return m_base;
265    }
set_first(BidiIterator i)266    void BOOST_REGEX_CALL set_first(BidiIterator i)
267    {
268       // set up prefix:
269       m_subs[1].second = i;
270       m_subs[1].matched = (m_subs[1].first != i);
271       // set up $0:
272       m_subs[2].first = i;
273       // zero out everything else:
274       for(size_type n = 3; n < m_subs.size(); ++n)
275       {
276          m_subs[n].first = m_subs[n].second = m_subs[0].second;
277          m_subs[n].matched = false;
278       }
279    }
set_first(BidiIterator i,size_type pos)280    void BOOST_REGEX_CALL set_first(BidiIterator i, size_type pos)
281    {
282       BOOST_ASSERT(pos+2 < m_subs.size());
283       if(pos)
284          m_subs[pos+2].first = i;
285       else
286          set_first(i);
287    }
288    void BOOST_REGEX_CALL maybe_assign(const match_results<BidiIterator, Allocator>& m);
289 
290 
291 private:
292    vector_type            m_subs; // subexpressions
293    BidiIterator   m_base; // where the search started from
294    sub_match<BidiIterator> m_null; // a null match
295 };
296 
297 template <class BidiIterator, class Allocator>
maybe_assign(const match_results<BidiIterator,Allocator> & m)298 void BOOST_REGEX_CALL match_results<BidiIterator, Allocator>::maybe_assign(const match_results<BidiIterator, Allocator>& m)
299 {
300    const_iterator p1, p2;
301    p1 = begin();
302    p2 = m.begin();
303    //
304    // Distances are measured from the start of *this* match, unless this isn't
305    // a valid match in which case we use the start of the whole sequence.  Note that
306    // no subsequent match-candidate can ever be to the left of the first match found.
307    // This ensures that when we are using bidirectional iterators, that distances
308    // measured are as short as possible, and therefore as efficient as possible
309    // to compute.  Finally note that we don't use the "matched" data member to test
310    // whether a sub-expression is a valid match, because partial matches set this
311    // to false for sub-expression 0.
312    //
313    BidiIterator end = this->suffix().second;
314    BidiIterator base = (p1->first == end) ? this->prefix().first : (*this)[0].first;
315    difference_type len1 = 0;
316    difference_type len2 = 0;
317    difference_type base1 = 0;
318    difference_type base2 = 0;
319    std::size_t i;
320    for(i = 0; i < size(); ++i, ++p1, ++p2)
321    {
322       //
323       // Leftmost takes priority over longest; handle special cases
324       // where distances need not be computed first (an optimisation
325       // for bidirectional iterators: ensure that we don't accidently
326       // compute the length of the whole sequence, as this can be really
327       // expensive).
328       //
329       if(p1->first == end)
330       {
331          if(p2->first != end)
332          {
333             // p2 must be better than p1, and no need to calculate
334             // actual distances:
335             base1 = 1;
336             base2 = 0;
337             break;
338          }
339          else
340          {
341             // *p1 and *p2 are either unmatched or match end-of sequence,
342             // either way no need to calculate distances:
343             if((p1->matched == false) && (p2->matched == true))
344                break;
345             if((p1->matched == true) && (p2->matched == false))
346                return;
347             continue;
348          }
349       }
350       else if(p2->first == end)
351       {
352          // p1 better than p2, and no need to calculate distances:
353          return;
354       }
355       base1 = ::boost::re_detail::distance(base, p1->first);
356       base2 = ::boost::re_detail::distance(base, p2->first);
357       BOOST_ASSERT(base1 >= 0);
358       BOOST_ASSERT(base2 >= 0);
359       if(base1 < base2) return;
360       if(base2 < base1) break;
361 
362       len1 = ::boost::re_detail::distance((BidiIterator)p1->first, (BidiIterator)p1->second);
363       len2 = ::boost::re_detail::distance((BidiIterator)p2->first, (BidiIterator)p2->second);
364       BOOST_ASSERT(len1 >= 0);
365       BOOST_ASSERT(len2 >= 0);
366       if((len1 != len2) || ((p1->matched == false) && (p2->matched == true)))
367          break;
368       if((p1->matched == true) && (p2->matched == false))
369          return;
370    }
371    if(i == size())
372       return;
373    if(base2 < base1)
374       *this = m;
375    else if((len2 > len1) || ((p1->matched == false) && (p2->matched == true)) )
376       *this = m;
377 }
378 
379 template <class BidiIterator, class Allocator>
swap(match_results<BidiIterator,Allocator> & a,match_results<BidiIterator,Allocator> & b)380 void swap(match_results<BidiIterator, Allocator>& a, match_results<BidiIterator, Allocator>& b)
381 {
382    a.swap(b);
383 }
384 
385 #ifndef BOOST_NO_STD_LOCALE
386 template <class charT, class traits, class BidiIterator, class Allocator>
387 std::basic_ostream<charT, traits>&
operator <<(std::basic_ostream<charT,traits> & os,const match_results<BidiIterator,Allocator> & s)388    operator << (std::basic_ostream<charT, traits>& os,
389                 const match_results<BidiIterator, Allocator>& s)
390 {
391    return (os << s.str());
392 }
393 #else
394 template <class BidiIterator, class Allocator>
operator <<(std::ostream & os,const match_results<BidiIterator,Allocator> & s)395 std::ostream& operator << (std::ostream& os,
396                            const match_results<BidiIterator, Allocator>& s)
397 {
398    return (os << s.str());
399 }
400 #endif
401 
402 #ifdef BOOST_MSVC
403 #pragma warning(pop)
404 #endif
405 } // namespace boost
406 
407 #ifdef BOOST_HAS_ABI_HEADERS
408 #  include BOOST_ABI_SUFFIX
409 #endif
410 
411 #endif
412 
413