1 /*
2  *
3  * Copyright (c) 1998-2009
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_V5_MATCH_RESULTS_HPP
20 #define BOOST_REGEX_V5_MATCH_RESULTS_HPP
21 
22 namespace boost{
23 #ifdef BOOST_REGEX_MSVC
24 #pragma warning(push)
25 #pragma warning(disable : 4251 4459)
26 #if BOOST_REGEX_MSVC < 1700
27 #     pragma warning(disable : 4231)
28 #endif
29 #  if BOOST_REGEX_MSVC < 1600
30 #     pragma warning(disable : 4660)
31 #  endif
32 #endif
33 
34 namespace BOOST_REGEX_DETAIL_NS{
35 
36 class named_subexpressions;
37 
38 }
39 
40 template <class BidiIterator, class Allocator>
41 class match_results
42 {
43 private:
44    typedef          std::vector<sub_match<BidiIterator>, Allocator> vector_type;
45 public:
46    typedef          sub_match<BidiIterator>                         value_type;
47    typedef typename std::allocator_traits<Allocator>::value_type const &    const_reference;
48    typedef          const_reference                                         reference;
49    typedef typename vector_type::const_iterator                             const_iterator;
50    typedef          const_iterator                                          iterator;
51    typedef typename std::iterator_traits<
52                                     BidiIterator>::difference_type          difference_type;
53    typedef typename std::allocator_traits<Allocator>::size_type             size_type;
54    typedef          Allocator                                               allocator_type;
55    typedef typename std::iterator_traits<
56                                     BidiIterator>::value_type               char_type;
57    typedef          std::basic_string<char_type>                            string_type;
58    typedef          BOOST_REGEX_DETAIL_NS::named_subexpressions             named_sub_type;
59 
60    // construct/copy/destroy:
match_results(const Allocator & a=Allocator ())61    explicit match_results(const Allocator& a = Allocator())
62       : m_subs(a), m_base(), m_null(), m_last_closed_paren(0), m_is_singular(true) {}
63    //
64    // IMPORTANT: in the code below, the crazy looking checks around m_is_singular are
65    // all required because it is illegal to copy a singular iterator.
66    // See https://svn.boost.org/trac/boost/ticket/3632.
67    //
match_results(const match_results & m)68    match_results(const match_results& m)
69       : m_subs(m.m_subs), m_base(), m_null(), m_named_subs(m.m_named_subs), m_last_closed_paren(m.m_last_closed_paren), m_is_singular(m.m_is_singular)
70    {
71       if(!m_is_singular)
72       {
73          m_base = m.m_base;
74          m_null = m.m_null;
75       }
76    }
operator =(const match_results & m)77    match_results& operator=(const match_results& m)
78    {
79       m_subs = m.m_subs;
80       m_named_subs = m.m_named_subs;
81       m_last_closed_paren = m.m_last_closed_paren;
82       m_is_singular = m.m_is_singular;
83       if(!m_is_singular)
84       {
85          m_base = m.m_base;
86          m_null = m.m_null;
87       }
88       return *this;
89    }
~match_results()90    ~match_results(){}
91 
92    // size:
size() const93    size_type size() const
94    { return empty() ? 0 : m_subs.size() - 2; }
max_size() const95    size_type max_size() const
96    { return m_subs.max_size(); }
empty() const97    bool empty() const
98    { return m_subs.size() < 2; }
99    // element access:
length(int sub=0) const100    difference_type length(int sub = 0) const
101    {
102       if(m_is_singular)
103          raise_logic_error();
104       sub += 2;
105       if((sub < (int)m_subs.size()) && (sub > 0))
106          return m_subs[sub].length();
107       return 0;
108    }
length(const char_type * sub) const109    difference_type length(const char_type* sub) const
110    {
111       if(m_is_singular)
112          raise_logic_error();
113       const char_type* sub_end = sub;
114       while(*sub_end) ++sub_end;
115       return length(named_subexpression_index(sub, sub_end));
116    }
117    template <class charT>
length(const charT * sub) const118    difference_type length(const charT* sub) const
119    {
120       if(m_is_singular)
121          raise_logic_error();
122       const charT* sub_end = sub;
123       while(*sub_end) ++sub_end;
124       return length(named_subexpression_index(sub, sub_end));
125    }
126    template <class charT, class Traits, class A>
length(const std::basic_string<charT,Traits,A> & sub) const127    difference_type length(const std::basic_string<charT, Traits, A>& sub) const
128    {
129       return length(sub.c_str());
130    }
position(size_type sub=0) const131    difference_type position(size_type sub = 0) const
132    {
133       if(m_is_singular)
134          raise_logic_error();
135       sub += 2;
136       if(sub < m_subs.size())
137       {
138          const sub_match<BidiIterator>& s = m_subs[sub];
139          if(s.matched || (sub == 2))
140          {
141             return std::distance((BidiIterator)(m_base), (BidiIterator)(s.first));
142          }
143       }
144       return ~static_cast<difference_type>(0);
145    }
position(const char_type * sub) const146    difference_type position(const char_type* sub) const
147    {
148       const char_type* sub_end = sub;
149       while(*sub_end) ++sub_end;
150       return position(named_subexpression_index(sub, sub_end));
151    }
152    template <class charT>
position(const charT * sub) const153    difference_type position(const charT* sub) const
154    {
155       const charT* sub_end = sub;
156       while(*sub_end) ++sub_end;
157       return position(named_subexpression_index(sub, sub_end));
158    }
159    template <class charT, class Traits, class A>
position(const std::basic_string<charT,Traits,A> & sub) const160    difference_type position(const std::basic_string<charT, Traits, A>& sub) const
161    {
162       return position(sub.c_str());
163    }
str(int sub=0) const164    string_type str(int sub = 0) const
165    {
166       if(m_is_singular)
167          raise_logic_error();
168       sub += 2;
169       string_type result;
170       if(sub < (int)m_subs.size() && (sub > 0))
171       {
172          const sub_match<BidiIterator>& s = m_subs[sub];
173          if(s.matched)
174          {
175             result = s.str();
176          }
177       }
178       return result;
179    }
str(const char_type * sub) const180    string_type str(const char_type* sub) const
181    {
182       return (*this)[sub].str();
183    }
184    template <class Traits, class A>
str(const std::basic_string<char_type,Traits,A> & sub) const185    string_type str(const std::basic_string<char_type, Traits, A>& sub) const
186    {
187       return (*this)[sub].str();
188    }
189    template <class charT>
str(const charT * sub) const190    string_type str(const charT* sub) const
191    {
192       return (*this)[sub].str();
193    }
194    template <class charT, class Traits, class A>
str(const std::basic_string<charT,Traits,A> & sub) const195    string_type str(const std::basic_string<charT, Traits, A>& sub) const
196    {
197       return (*this)[sub].str();
198    }
operator [](int sub) const199    const_reference operator[](int sub) const
200    {
201       if(m_is_singular && m_subs.empty())
202          raise_logic_error();
203       sub += 2;
204       if(sub < (int)m_subs.size() && (sub >= 0))
205       {
206          return m_subs[sub];
207       }
208       return m_null;
209    }
210    //
211    // Named sub-expressions:
212    //
named_subexpression(const char_type * i,const char_type * j) const213    const_reference named_subexpression(const char_type* i, const char_type* j) const
214    {
215       //
216       // Scan for the leftmost *matched* subexpression with the specified named:
217       //
218       if(m_is_singular)
219          raise_logic_error();
220       BOOST_REGEX_DETAIL_NS::named_subexpressions::range_type r = m_named_subs->equal_range(i, j);
221       while((r.first != r.second) && ((*this)[r.first->index].matched == false))
222          ++r.first;
223       return r.first != r.second ? (*this)[r.first->index] : m_null;
224    }
225    template <class charT>
named_subexpression(const charT * i,const charT * j) const226    const_reference named_subexpression(const charT* i, const charT* j) const
227    {
228       static_assert(sizeof(charT) <= sizeof(char_type), "Failed internal logic");
229       if(i == j)
230          return m_null;
231       std::vector<char_type> s;
232       while(i != j)
233          s.insert(s.end(), *i++);
234       return named_subexpression(&*s.begin(), &*s.begin() + s.size());
235    }
named_subexpression_index(const char_type * i,const char_type * j) const236    int named_subexpression_index(const char_type* i, const char_type* j) const
237    {
238       //
239       // Scan for the leftmost *matched* subexpression with the specified named.
240       // If none found then return the leftmost expression with that name,
241       // otherwise an invalid index:
242       //
243       if(m_is_singular)
244          raise_logic_error();
245       BOOST_REGEX_DETAIL_NS::named_subexpressions::range_type s, r;
246       s = r = m_named_subs->equal_range(i, j);
247       while((r.first != r.second) && ((*this)[r.first->index].matched == false))
248          ++r.first;
249       if(r.first == r.second)
250          r = s;
251       return r.first != r.second ? r.first->index : -20;
252    }
253    template <class charT>
named_subexpression_index(const charT * i,const charT * j) const254    int named_subexpression_index(const charT* i, const charT* j) const
255    {
256       static_assert(sizeof(charT) <= sizeof(char_type), "Failed internal logic");
257       if(i == j)
258          return -20;
259       std::vector<char_type> s;
260       while(i != j)
261          s.insert(s.end(), *i++);
262       return named_subexpression_index(&*s.begin(), &*s.begin() + s.size());
263    }
264    template <class Traits, class A>
operator [](const std::basic_string<char_type,Traits,A> & s) const265    const_reference operator[](const std::basic_string<char_type, Traits, A>& s) const
266    {
267       return named_subexpression(s.c_str(), s.c_str() + s.size());
268    }
operator [](const char_type * p) const269    const_reference operator[](const char_type* p) const
270    {
271       const char_type* e = p;
272       while(*e) ++e;
273       return named_subexpression(p, e);
274    }
275 
276    template <class charT>
operator [](const charT * p) const277    const_reference operator[](const charT* p) const
278    {
279       static_assert(sizeof(charT) <= sizeof(char_type), "Failed internal logic");
280       if(*p == 0)
281          return m_null;
282       std::vector<char_type> s;
283       while(*p)
284          s.insert(s.end(), *p++);
285       return named_subexpression(&*s.begin(), &*s.begin() + s.size());
286    }
287    template <class charT, class Traits, class A>
operator [](const std::basic_string<charT,Traits,A> & ns) const288    const_reference operator[](const std::basic_string<charT, Traits, A>& ns) const
289    {
290       static_assert(sizeof(charT) <= sizeof(char_type), "Failed internal logic");
291       if(ns.empty())
292          return m_null;
293       std::vector<char_type> s;
294       for(unsigned i = 0; i < ns.size(); ++i)
295          s.insert(s.end(), ns[i]);
296       return named_subexpression(&*s.begin(), &*s.begin() + s.size());
297    }
298 
prefix() const299    const_reference prefix() const
300    {
301       if(m_is_singular)
302          raise_logic_error();
303       return (*this)[-1];
304    }
305 
suffix() const306    const_reference suffix() const
307    {
308       if(m_is_singular)
309          raise_logic_error();
310       return (*this)[-2];
311    }
begin() const312    const_iterator begin() const
313    {
314       return (m_subs.size() > 2) ? (m_subs.begin() + 2) : m_subs.end();
315    }
end() const316    const_iterator end() const
317    {
318       return m_subs.end();
319    }
320    // format:
321    template <class OutputIterator, class Functor>
322    OutputIterator format(OutputIterator out,
323                          Functor fmt,
324                          match_flag_type flags = format_default) const
325    {
326       if(m_is_singular)
327          raise_logic_error();
328       typedef typename BOOST_REGEX_DETAIL_NS::compute_functor_type<Functor, match_results<BidiIterator, Allocator>, OutputIterator>::type F;
329       F func(fmt);
330       return func(*this, out, flags);
331    }
332    template <class Functor>
format(Functor fmt,match_flag_type flags=format_default) const333    string_type format(Functor fmt, match_flag_type flags = format_default) const
334    {
335       if(m_is_singular)
336          raise_logic_error();
337       std::basic_string<char_type> result;
338       BOOST_REGEX_DETAIL_NS::string_out_iterator<std::basic_string<char_type> > i(result);
339 
340       typedef typename BOOST_REGEX_DETAIL_NS::compute_functor_type<Functor, match_results<BidiIterator, Allocator>, BOOST_REGEX_DETAIL_NS::string_out_iterator<std::basic_string<char_type> > >::type F;
341       F func(fmt);
342 
343       func(*this, i, flags);
344       return result;
345    }
346    // format with locale:
347    template <class OutputIterator, class Functor, class RegexT>
348    OutputIterator format(OutputIterator out,
349                          Functor fmt,
350                          match_flag_type flags,
351                          const RegexT& re) const
352    {
353       if(m_is_singular)
354          raise_logic_error();
355       typedef ::boost::regex_traits_wrapper<typename RegexT::traits_type> traits_type;
356       typedef typename BOOST_REGEX_DETAIL_NS::compute_functor_type<Functor, match_results<BidiIterator, Allocator>, OutputIterator, traits_type>::type F;
357       F func(fmt);
358       return func(*this, out, flags, re.get_traits());
359    }
360    template <class RegexT, class Functor>
format(Functor fmt,match_flag_type flags,const RegexT & re) const361    string_type format(Functor fmt,
362                       match_flag_type flags,
363                       const RegexT& re) const
364    {
365       if(m_is_singular)
366          raise_logic_error();
367       typedef ::boost::regex_traits_wrapper<typename RegexT::traits_type> traits_type;
368       std::basic_string<char_type> result;
369       BOOST_REGEX_DETAIL_NS::string_out_iterator<std::basic_string<char_type> > i(result);
370 
371       typedef typename BOOST_REGEX_DETAIL_NS::compute_functor_type<Functor, match_results<BidiIterator, Allocator>, BOOST_REGEX_DETAIL_NS::string_out_iterator<std::basic_string<char_type> >, traits_type >::type F;
372       F func(fmt);
373 
374       func(*this, i, flags, re.get_traits());
375       return result;
376    }
377 
get_last_closed_paren() const378    const_reference get_last_closed_paren()const
379    {
380       if(m_is_singular)
381          raise_logic_error();
382       return m_last_closed_paren == 0 ? m_null : (*this)[m_last_closed_paren];
383    }
384 
get_allocator() const385    allocator_type get_allocator() const
386    {
387       return m_subs.get_allocator();
388    }
swap(match_results & that)389    void swap(match_results& that)
390    {
391       std::swap(m_subs, that.m_subs);
392       std::swap(m_named_subs, that.m_named_subs);
393       std::swap(m_last_closed_paren, that.m_last_closed_paren);
394       if(m_is_singular)
395       {
396          if(!that.m_is_singular)
397          {
398             m_base = that.m_base;
399             m_null = that.m_null;
400          }
401       }
402       else if(that.m_is_singular)
403       {
404          that.m_base = m_base;
405          that.m_null = m_null;
406       }
407       else
408       {
409          std::swap(m_base, that.m_base);
410          std::swap(m_null, that.m_null);
411       }
412       std::swap(m_is_singular, that.m_is_singular);
413    }
operator ==(const match_results & that) const414    bool operator==(const match_results& that)const
415    {
416       if(m_is_singular)
417       {
418          return that.m_is_singular;
419       }
420       else if(that.m_is_singular)
421       {
422          return false;
423       }
424       return (m_subs == that.m_subs) && (m_base == that.m_base) && (m_last_closed_paren == that.m_last_closed_paren);
425    }
operator !=(const match_results & that) const426    bool operator!=(const match_results& that)const
427    { return !(*this == that); }
428 
429 #ifdef BOOST_REGEX_MATCH_EXTRA
430    typedef typename sub_match<BidiIterator>::capture_sequence_type capture_sequence_type;
431 
captures(int i) const432    const capture_sequence_type& captures(int i)const
433    {
434       if(m_is_singular)
435          raise_logic_error();
436       return (*this)[i].captures();
437    }
438 #endif
439 
440    //
441    // private access functions:
set_second(BidiIterator i)442    void  set_second(BidiIterator i)
443    {
444       BOOST_REGEX_ASSERT(m_subs.size() > 2);
445       m_subs[2].second = i;
446       m_subs[2].matched = true;
447       m_subs[0].first = i;
448       m_subs[0].matched = (m_subs[0].first != m_subs[0].second);
449       m_null.first = i;
450       m_null.second = i;
451       m_null.matched = false;
452       m_is_singular = false;
453    }
454 
set_second(BidiIterator i,size_type pos,bool m=true,bool escape_k=false)455    void  set_second(BidiIterator i, size_type pos, bool m = true, bool escape_k = false)
456    {
457       if(pos)
458          m_last_closed_paren = static_cast<int>(pos);
459       pos += 2;
460       BOOST_REGEX_ASSERT(m_subs.size() > pos);
461       m_subs[pos].second = i;
462       m_subs[pos].matched = m;
463       if((pos == 2) && !escape_k)
464       {
465          m_subs[0].first = i;
466          m_subs[0].matched = (m_subs[0].first != m_subs[0].second);
467          m_null.first = i;
468          m_null.second = i;
469          m_null.matched = false;
470          m_is_singular = false;
471       }
472    }
set_size(size_type n,BidiIterator i,BidiIterator j)473    void  set_size(size_type n, BidiIterator i, BidiIterator j)
474    {
475       value_type v(j);
476       size_type len = m_subs.size();
477       if(len > n + 2)
478       {
479          m_subs.erase(m_subs.begin()+n+2, m_subs.end());
480          std::fill(m_subs.begin(), m_subs.end(), v);
481       }
482       else
483       {
484          std::fill(m_subs.begin(), m_subs.end(), v);
485          if(n+2 != len)
486             m_subs.insert(m_subs.end(), n+2-len, v);
487       }
488       m_subs[1].first = i;
489       m_last_closed_paren = 0;
490    }
set_base(BidiIterator pos)491    void  set_base(BidiIterator pos)
492    {
493       m_base = pos;
494    }
base() const495    BidiIterator base()const
496    {
497       return m_base;
498    }
set_first(BidiIterator i)499    void  set_first(BidiIterator i)
500    {
501       BOOST_REGEX_ASSERT(m_subs.size() > 2);
502       // set up prefix:
503       m_subs[1].second = i;
504       m_subs[1].matched = (m_subs[1].first != i);
505       // set up $0:
506       m_subs[2].first = i;
507       // zero out everything else:
508       for(size_type n = 3; n < m_subs.size(); ++n)
509       {
510          m_subs[n].first = m_subs[n].second = m_subs[0].second;
511          m_subs[n].matched = false;
512       }
513    }
set_first(BidiIterator i,size_type pos,bool escape_k=false)514    void  set_first(BidiIterator i, size_type pos, bool escape_k = false)
515    {
516       BOOST_REGEX_ASSERT(pos+2 < m_subs.size());
517       if(pos || escape_k)
518       {
519          m_subs[pos+2].first = i;
520          if(escape_k)
521          {
522             m_subs[1].second = i;
523             m_subs[1].matched = (m_subs[1].first != m_subs[1].second);
524          }
525       }
526       else
527          set_first(i);
528    }
529    void  maybe_assign(const match_results<BidiIterator, Allocator>& m);
530 
set_named_subs(std::shared_ptr<named_sub_type> subs)531    void  set_named_subs(std::shared_ptr<named_sub_type> subs)
532    {
533       m_named_subs = subs;
534    }
535 
536 private:
537    //
538    // Error handler called when an uninitialized match_results is accessed:
539    //
raise_logic_error()540    static void raise_logic_error()
541    {
542       std::logic_error e("Attempt to access an uninitialized boost::match_results<> class.");
543 #ifndef BOOST_REGEX_STANDALONE
544       boost::throw_exception(e);
545 #else
546       throw e;
547 #endif
548    }
549 
550 
551    vector_type            m_subs;                      // subexpressions
552    BidiIterator   m_base;                              // where the search started from
553    sub_match<BidiIterator> m_null;                     // a null match
554    std::shared_ptr<named_sub_type> m_named_subs;     // Shared copy of named subs in the regex object
555    int m_last_closed_paren;                            // Last ) to be seen - used for formatting
556    bool m_is_singular;                                 // True if our stored iterators are singular
557 };
558 
559 template <class BidiIterator, class Allocator>
maybe_assign(const match_results<BidiIterator,Allocator> & m)560 void  match_results<BidiIterator, Allocator>::maybe_assign(const match_results<BidiIterator, Allocator>& m)
561 {
562    if(m_is_singular)
563    {
564       *this = m;
565       return;
566    }
567    const_iterator p1, p2;
568    p1 = begin();
569    p2 = m.begin();
570    //
571    // Distances are measured from the start of *this* match, unless this isn't
572    // a valid match in which case we use the start of the whole sequence.  Note that
573    // no subsequent match-candidate can ever be to the left of the first match found.
574    // This ensures that when we are using bidirectional iterators, that distances
575    // measured are as short as possible, and therefore as efficient as possible
576    // to compute.  Finally note that we don't use the "matched" data member to test
577    // whether a sub-expression is a valid match, because partial matches set this
578    // to false for sub-expression 0.
579    //
580    BidiIterator l_end = this->suffix().second;
581    BidiIterator l_base = (p1->first == l_end) ? this->prefix().first : (*this)[0].first;
582    difference_type len1 = 0;
583    difference_type len2 = 0;
584    difference_type base1 = 0;
585    difference_type base2 = 0;
586    std::size_t i;
587    for(i = 0; i < size(); ++i, ++p1, ++p2)
588    {
589       //
590       // Leftmost takes priority over longest; handle special cases
591       // where distances need not be computed first (an optimisation
592       // for bidirectional iterators: ensure that we don't accidently
593       // compute the length of the whole sequence, as this can be really
594       // expensive).
595       //
596       if(p1->first == l_end)
597       {
598          if(p2->first != l_end)
599          {
600             // p2 must be better than p1, and no need to calculate
601             // actual distances:
602             base1 = 1;
603             base2 = 0;
604             break;
605          }
606          else
607          {
608             // *p1 and *p2 are either unmatched or match end-of sequence,
609             // either way no need to calculate distances:
610             if((p1->matched == false) && (p2->matched == true))
611                break;
612             if((p1->matched == true) && (p2->matched == false))
613                return;
614             continue;
615          }
616       }
617       else if(p2->first == l_end)
618       {
619          // p1 better than p2, and no need to calculate distances:
620          return;
621       }
622       base1 = std::distance(l_base, p1->first);
623       base2 = std::distance(l_base, p2->first);
624       BOOST_REGEX_ASSERT(base1 >= 0);
625       BOOST_REGEX_ASSERT(base2 >= 0);
626       if(base1 < base2) return;
627       if(base2 < base1) break;
628 
629       len1 = std::distance((BidiIterator)p1->first, (BidiIterator)p1->second);
630       len2 = std::distance((BidiIterator)p2->first, (BidiIterator)p2->second);
631       BOOST_REGEX_ASSERT(len1 >= 0);
632       BOOST_REGEX_ASSERT(len2 >= 0);
633       if((len1 != len2) || ((p1->matched == false) && (p2->matched == true)))
634          break;
635       if((p1->matched == true) && (p2->matched == false))
636          return;
637    }
638    if(i == size())
639       return;
640    if(base2 < base1)
641       *this = m;
642    else if((len2 > len1) || ((p1->matched == false) && (p2->matched == true)) )
643       *this = m;
644 }
645 
646 template <class BidiIterator, class Allocator>
swap(match_results<BidiIterator,Allocator> & a,match_results<BidiIterator,Allocator> & b)647 void swap(match_results<BidiIterator, Allocator>& a, match_results<BidiIterator, Allocator>& b)
648 {
649    a.swap(b);
650 }
651 
652 template <class charT, class traits, class BidiIterator, class Allocator>
653 std::basic_ostream<charT, traits>&
operator <<(std::basic_ostream<charT,traits> & os,const match_results<BidiIterator,Allocator> & s)654    operator << (std::basic_ostream<charT, traits>& os,
655                 const match_results<BidiIterator, Allocator>& s)
656 {
657    return (os << s.str());
658 }
659 
660 #ifdef BOOST_REGEX_MSVC
661 #pragma warning(pop)
662 #endif
663 } // namespace boost
664 
665 #endif
666 
667 
668