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