1///////////////////////////////////////////////////////////////////////////////
2/// \file match_results.hpp
3/// Contains the definition of the match_results type and associated helpers.
4/// The match_results type holds the results of a regex_match() or
5/// regex_search() operation.
6//
7// Copyright 2008 Eric Niebler. Distributed under the Boost
8// Software License, Version 1.0. (See accompanying file
9// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10//
11// Acknowledgements: Thanks to Markus Schoepflin for helping to track down
12// a tricky formatting bug on HP Tru64, and to Steven Watanabe for suggesting
13// the fix.
14
15#ifndef BOOST_XPRESSIVE_MATCH_RESULTS_HPP_EAN_10_04_2005
16#define BOOST_XPRESSIVE_MATCH_RESULTS_HPP_EAN_10_04_2005
17
18// MS compatible compilers support #pragma once
19#if defined(_MSC_VER)
20# pragma once
21#endif
22
23#include <map>
24#include <string>
25#include <vector>
26#include <utility>
27#include <iterator>
28#include <typeinfo>
29#include <algorithm>
30#include <boost/config.hpp>
31#include <boost/assert.hpp>
32#include <boost/integer.hpp>
33#include <boost/mpl/if.hpp>
34#include <boost/mpl/not.hpp>
35#include <boost/mpl/size_t.hpp>
36#include <boost/mpl/assert.hpp>
37#include <boost/intrusive_ptr.hpp>
38#include <boost/throw_exception.hpp>
39#include <boost/iterator_adaptors.hpp>
40#include <boost/utility/enable_if.hpp>
41#include <boost/detail/workaround.hpp>
42#include <boost/numeric/conversion/converter.hpp>
43#include <boost/optional.hpp>
44#include <boost/range/end.hpp>
45#include <boost/range/begin.hpp>
46#include <boost/range/as_literal.hpp>
47#include <boost/range/const_iterator.hpp>
48#include <boost/type_traits/is_function.hpp>
49#if BOOST_ITERATOR_ADAPTORS_VERSION >= 0x0200
50# include <boost/iterator/filter_iterator.hpp>
51#endif
52#include <boost/xpressive/regex_constants.hpp>
53#include <boost/xpressive/detail/detail_fwd.hpp>
54#include <boost/xpressive/detail/core/regex_impl.hpp>
55#include <boost/xpressive/detail/core/sub_match_vector.hpp>
56#include <boost/xpressive/detail/utility/sequence_stack.hpp>
57#include <boost/xpressive/detail/core/results_cache.hpp>
58#include <boost/xpressive/detail/utility/literals.hpp>
59#include <boost/xpressive/detail/utility/algorithm.hpp>
60#include <boost/xpressive/detail/utility/counted_base.hpp>
61// Doxygen can't handle proto :-(
62#ifndef BOOST_XPRESSIVE_DOXYGEN_INVOKED
63# include <boost/proto/proto_fwd.hpp>
64# include <boost/proto/traits.hpp>
65#endif
66
67namespace boost { namespace xpressive { namespace detail
68{
69
70///////////////////////////////////////////////////////////////////////////////
71// type_info_less
72//
73struct type_info_less
74{
75 bool operator()(std::type_info const *left, std::type_info const *right) const
76 {
77 return 0 != left->before(arg: *right);
78 }
79};
80
81///////////////////////////////////////////////////////////////////////////////
82// ActionArgBinding
83//
84struct ActionArgBinding
85 : proto::assign<proto::terminal<action_arg<proto::_, proto::_> >, proto::terminal<proto::_> >
86{
87};
88
89///////////////////////////////////////////////////////////////////////////////
90// results_extras
91//
92template<typename BidiIter>
93struct results_extras
94 : counted_base<results_extras<BidiIter> >
95{
96 sequence_stack<sub_match_impl<BidiIter> > sub_match_stack_;
97 results_cache<BidiIter> results_cache_;
98};
99
100///////////////////////////////////////////////////////////////////////////////
101// char_overflow_handler_
102//
103struct char_overflow_handler_
104{
105 void operator ()(numeric::range_check_result result) const // throw(regex_error)
106 {
107 if(numeric::cInRange != result)
108 {
109 BOOST_THROW_EXCEPTION(
110 regex_error(
111 regex_constants::error_escape
112 , "character escape too large to fit in target character type"
113 )
114 );
115 }
116 }
117};
118
119///////////////////////////////////////////////////////////////////////////////
120// transform_op enum
121//
122enum transform_op { op_none = 0, op_upper = 1, op_lower = 2 };
123enum transform_scope { scope_next = 0, scope_rest = 1 };
124
125///////////////////////////////////////////////////////////////////////////////
126// case_converting_iterator
127//
128template<typename OutputIterator, typename Char>
129struct case_converting_iterator
130 : std::iterator<std::output_iterator_tag, Char, void, void, case_converting_iterator<OutputIterator, Char> >
131{
132 case_converting_iterator(OutputIterator const &out, traits<Char> const *tr)
133 : out_(out)
134 , traits_(tr)
135 , next_(op_none)
136 , rest_(op_none)
137 {}
138
139 OutputIterator base() const
140 {
141 return this->out_;
142 }
143
144 case_converting_iterator &operator ++()
145 {
146 ++this->out_;
147 this->next_ = op_none;
148 return *this;
149 }
150
151 case_converting_iterator operator ++(int)
152 {
153 case_converting_iterator tmp(*this);
154 ++*this;
155 return tmp;
156 }
157
158 case_converting_iterator &operator *()
159 {
160 return *this;
161 }
162
163 friend bool set_transform(case_converting_iterator &iter, transform_op trans, transform_scope scope)
164 {
165 BOOST_ASSERT(scope == scope_next || scope == scope_rest);
166 if(scope == scope_next)
167 iter.next_ = trans;
168 else
169 iter.rest_ = trans;
170 return true;
171 }
172
173 case_converting_iterator &operator =(Char ch)
174 {
175 switch(this->next_ ? this->next_ : this->rest_)
176 {
177 case op_lower:
178 ch = this->traits_->tolower(ch);
179 break;
180
181 case op_upper:
182 ch = this->traits_->toupper(ch);
183 break;
184
185 default:;
186 }
187
188 *this->out_ = ch;
189 return *this;
190 }
191
192private:
193 OutputIterator out_;
194 traits<Char> const *traits_;
195 transform_op next_, rest_;
196};
197
198template<typename Iterator>
199inline bool set_transform(Iterator &, transform_op, transform_scope)
200{
201 return false;
202}
203
204///////////////////////////////////////////////////////////////////////////////
205// noop_output_iterator
206//
207template<typename Char>
208struct noop_output_iterator
209 : std::iterator<std::output_iterator_tag, Char, void, void, noop_output_iterator<Char> >
210{
211 noop_output_iterator &operator ++()
212 {
213 return *this;
214 }
215
216 noop_output_iterator &operator ++(int)
217 {
218 return *this;
219 }
220
221 noop_output_iterator &operator *()
222 {
223 return *this;
224 }
225
226 noop_output_iterator &operator =(Char const &)
227 {
228 return *this;
229 }
230};
231
232struct any_type { any_type(...); };
233typedef char no_type;
234typedef char (&unary_type)[2];
235typedef char (&binary_type)[3];
236typedef char (&ternary_type)[4];
237
238no_type check_is_formatter(unary_type, binary_type, ternary_type);
239
240template<typename T>
241unary_type check_is_formatter(T const &, binary_type, ternary_type);
242
243template<typename T>
244binary_type check_is_formatter(unary_type, T const &, ternary_type);
245
246template<typename T, typename U>
247binary_type check_is_formatter(T const &, U const &, ternary_type);
248
249template<typename T>
250ternary_type check_is_formatter(unary_type, binary_type, T const &);
251
252template<typename T, typename U>
253ternary_type check_is_formatter(T const &, binary_type, U const &);
254
255template<typename T, typename U>
256ternary_type check_is_formatter(unary_type, T const &, U const &);
257
258template<typename T, typename U, typename V>
259ternary_type check_is_formatter(T const &, U const &, V const &);
260
261struct unary_binary_ternary
262{
263 typedef unary_type (*unary_fun)(any_type);
264 typedef binary_type (*binary_fun)(any_type, any_type);
265 typedef ternary_type (*ternary_fun)(any_type, any_type, any_type);
266 operator unary_fun();
267 operator binary_fun();
268 operator ternary_fun();
269};
270
271template<typename Formatter, bool IsFunction = is_function<Formatter>::value>
272struct formatter_wrapper
273 : Formatter
274 , unary_binary_ternary
275{
276 formatter_wrapper();
277};
278
279template<typename Formatter>
280struct formatter_wrapper<Formatter, true>
281 : unary_binary_ternary
282{
283 operator Formatter *();
284};
285
286template<typename Formatter>
287struct formatter_wrapper<Formatter *, false>
288 : unary_binary_ternary
289{
290 operator Formatter *();
291};
292
293template<typename Formatter, typename What, typename Out, typename Void = void>
294struct formatter_arity
295{
296 static formatter_wrapper<Formatter> &formatter;
297 static What &what;
298 static Out &out;
299 BOOST_STATIC_CONSTANT(
300 std::size_t
301 , value = sizeof(
302 check_is_formatter(
303 formatter(what)
304 , formatter(what, out)
305 , formatter(what, out, regex_constants::format_default)
306 )
307 ) - 1
308 );
309 typedef mpl::size_t<value> type;
310};
311
312template<typename Formatter, typename What, typename Out>
313struct formatter_arity<Formatter, What, Out, typename Formatter::proto_is_expr_>
314 : mpl::size_t<4>
315{};
316
317template<typename T>
318struct is_char_ptr
319 : mpl::false_
320{};
321
322template<typename T>
323struct is_char_ptr<T *>
324 : mpl::not_<is_function<T> >
325{};
326
327#if BOOST_WORKAROUND(__GNUC__, == 4) && (__GNUC_MINOR__ == 0)
328// work around gcc-4.0.1 compiler bug wrt function references
329template<typename T>
330typename mpl::if_<is_function<T>, T *, T const &>::type
331as_callable(T const &t)
332{
333 return t;
334}
335#endif
336
337} // detail
338
339///////////////////////////////////////////////////////////////////////////////
340// match_results
341/// \brief Class template match_results\<\> holds the results of a regex_match() or a
342/// regex_search() as a collection of sub_match objects.
343///
344/// Class template match_results\<\> denotes a collection of sequences representing the result of
345/// a regular expression match. Storage for the collection is allocated and freed as necessary by
346/// the member functions of class match_results\<\>.
347///
348/// The class template match_results\<\> conforms to the requirements of a Sequence, as specified
349/// in (lib.sequence.reqmts), except that only operations defined for const-qualified Sequences are
350/// supported.
351template<typename BidiIter>
352struct match_results
353{
354private:
355 /// INTERNAL ONLY
356 ///
357 struct dummy { int i_; };
358 typedef int dummy::*bool_type;
359
360public:
361 typedef typename iterator_value<BidiIter>::type char_type;
362 typedef typename detail::string_type<char_type>::type string_type;
363 typedef std::size_t size_type;
364 typedef sub_match<BidiIter> value_type;
365 typedef typename iterator_difference<BidiIter>::type difference_type;
366 typedef value_type const &reference;
367 typedef value_type const &const_reference;
368
369 typedef typename detail::sub_match_vector<BidiIter>::iterator iterator;
370 typedef typename detail::sub_match_vector<BidiIter>::const_iterator const_iterator;
371 typedef typename detail::nested_results<BidiIter> nested_results_type;
372
373 /// \post regex_id() == 0
374 /// \post size() == 0
375 /// \post empty() == true
376 /// \post str() == string_type()
377 match_results()
378 : regex_id_(0)
379 , sub_matches_()
380 , base_()
381 , prefix_()
382 , suffix_()
383 , nested_results_()
384 , extras_ptr_()
385 , traits_()
386 , args_()
387 , named_marks_()
388 {
389 }
390
391 /// \param that The match_results object to copy
392 /// \post regex_id() == that.regex_id().
393 /// \post size() == that.size().
394 /// \post empty() == that.empty().
395 /// \post str(n) == that.str(n) for all positive integers n \< that.size().
396 /// \post prefix() == that.prefix().
397 /// \post suffix() == that.suffix().
398 /// \post (*this)[n] == that[n] for all positive integers n \< that.size().
399 /// \post length(n) == that.length(n) for all positive integers n \< that.size().
400 /// \post position(n) == that.position(n) for all positive integers n \< that.size().
401 match_results(match_results<BidiIter> const &that)
402 : regex_id_(that.regex_id_)
403 , sub_matches_()
404 , base_()
405 , prefix_()
406 , suffix_()
407 , nested_results_()
408 , extras_ptr_()
409 , traits_()
410 , args_(that.args_)
411 , named_marks_(that.named_marks_)
412 {
413 if(that)
414 {
415 extras_type &extras = this->get_extras_();
416 std::size_t size = that.sub_matches_.size();
417 detail::sub_match_impl<BidiIter> *sub_matches = extras.sub_match_stack_.push_sequence(size, detail::sub_match_impl<BidiIter>(*that.base_), detail::fill);
418 detail::core_access<BidiIter>::init_sub_match_vector(this->sub_matches_, sub_matches, size, that.sub_matches_);
419
420 this->base_ = that.base_;
421 this->prefix_ = that.prefix_;
422 this->suffix_ = that.suffix_;
423 // BUGBUG this doesn't share the extras::sequence_stack
424 this->nested_results_ = that.nested_results_;
425 this->traits_ = that.traits_;
426 }
427 }
428
429 ~match_results()
430 {
431 }
432
433 /// \param that The match_results object to copy.
434 /// \post regex_id() == that.regex_id().
435 /// \post size() == that.size().
436 /// \post empty() == that.empty().
437 /// \post str(n) == that.str(n) for all positive integers n \< that.size().
438 /// \post prefix() == that.prefix().
439 /// \post suffix() == that.suffix().
440 /// \post (*this)[n] == that[n] for all positive integers n \< that.size().
441 /// \post length(n) == that.length(n) for all positive integers n \< that.size().
442 /// \post position(n) == that.position(n) for all positive integers n \< that.size().
443 match_results<BidiIter> &operator =(match_results<BidiIter> const &that)
444 {
445 match_results<BidiIter>(that).swap(*this);
446 return *this;
447 }
448
449 /// Returns one plus the number of marked sub-expressions in the regular
450 /// expression that was matched if *this represents the result of a
451 /// successful match. Otherwise returns 0.
452 size_type size() const
453 {
454 return this->sub_matches_.size();
455 }
456
457 /// Returns size() == 0.
458 ///
459 bool empty() const
460 {
461 return 0 == this->size();
462 }
463
464 /// Returns (*this)[sub].length().
465 ///
466 difference_type length(size_type sub = 0) const
467 {
468 return this->sub_matches_[ sub ].length();
469 }
470
471 /// If !(*this)[sub].matched then returns -1. Otherwise returns std::distance(base, (*this)[sub].first),
472 /// where base is the start iterator of the sequence that was searched. [Note - unless this is part
473 /// of a repeated search with a regex_iterator then base is the same as prefix().first - end note]
474 difference_type position(size_type sub = 0) const
475 {
476 return this->sub_matches_[ sub ].matched ? std::distance(*this->base_, this->sub_matches_[ sub ].first) : -1;
477 }
478
479 /// Returns (*this)[sub].str().
480 ///
481 string_type str(size_type sub = 0) const
482 {
483 return this->sub_matches_[ sub ].str();
484 }
485
486 /// Returns a reference to the sub_match object representing the sequence that
487 /// matched marked sub-expression sub. If sub == 0 then returns a reference to
488 /// a sub_match object representing the sequence that matched the whole regular
489 /// expression. If sub >= size() then returns a sub_match object representing an
490 /// unmatched sub-expression.
491 template<typename Sub>
492 const_reference operator [](Sub const &sub) const
493 {
494 return this->at_(sub);
495 }
496
497 /// Returns a reference to the sub_match object representing the character sequence from
498 /// the start of the string being matched/searched, to the start of the match found.
499 ///
500 /// \pre (*this)[0].matched is true
501 const_reference prefix() const
502 {
503 return this->prefix_ ? *this->prefix_ : this->sub_matches_[this->sub_matches_.size()];
504 }
505
506 /// Returns a reference to the sub_match object representing the character sequence from
507 /// the end of the match found to the end of the string being matched/searched.
508 ///
509 /// \pre (*this)[0].matched is true
510 const_reference suffix() const
511 {
512 return this->suffix_ ? *this->suffix_ : this->sub_matches_[this->sub_matches_.size()];
513 }
514
515 /// Returns a starting iterator that enumerates over all the marked sub-expression matches
516 /// stored in *this.
517 ///
518 const_iterator begin() const
519 {
520 return this->sub_matches_.begin();
521 }
522
523 /// Returns a terminating iterator that enumerates over all the marked sub-expression
524 /// matches stored in *this.
525 ///
526 const_iterator end() const
527 {
528 return this->sub_matches_.end();
529 }
530
531 /// Returns a true value if (*this)[0].matched, else returns a false value.
532 ///
533 operator bool_type() const
534 {
535 return (!this->empty() && this->sub_matches_[ 0 ].matched) ? &dummy::i_ : 0;
536 }
537
538 /// Returns true if empty() || !(*this)[0].matched, else returns false.
539 ///
540 bool operator !() const
541 {
542 return this->empty() || !this->sub_matches_[ 0 ].matched;
543 }
544
545 /// Returns the id of the basic_regex object most recently used with this match_results object.
546 ///
547 regex_id_type regex_id() const
548 {
549 return this->regex_id_;
550 }
551
552 /// Returns a Sequence of nested match_results elements.
553 ///
554 nested_results_type const &nested_results() const
555 {
556 return this->nested_results_;
557 }
558
559 /// If \c Format models \c ForwardRange or is a null-terminated string, this function
560 /// copies the character sequence in \c fmt to \c OutputIterator \c out. For each format
561 /// specifier or escape sequence in \c fmt, replace that sequence with either the character(s) it
562 /// represents, or the sequence within <tt>*this</tt> to which it refers. The bitmasks specified in flags
563 /// determines what format specifiers or escape sequences are recognized. By default, this is the
564 /// format used by ECMA-262, ECMAScript Language Specification, Chapter 15 part 5.4.11 String.prototype.replace.
565 ///
566 /// Otherwise, if \c Format models <tt>Callable\<match_results\<BidiIter\>, OutputIterator, regex_constants::match_flag_type\></tt>,
567 /// this function returns <tt>fmt(*this, out, flags)</tt>.
568 ///
569 /// Otherwise, if \c Format models <tt>Callable\<match_results\<BidiIter\>, OutputIterator\></tt>, this function
570 /// returns <tt>fmt(*this, out)</tt>.
571 ///
572 /// Otherwise, if \c Format models <tt>Callable\<match_results\<BidiIter\> \></tt>, this function
573 /// returns <tt>std::copy(x.begin(), x.end(), out)</tt>, where \c x is the result of
574 /// calling <tt>fmt(*this)</tt>.
575 template<typename Format, typename OutputIterator>
576 OutputIterator format
577 (
578 OutputIterator out
579 , Format const &fmt
580 , regex_constants::match_flag_type flags = regex_constants::format_default
581 , typename disable_if<detail::is_char_ptr<Format> >::type * = 0
582 ) const
583 {
584 // Is this a formatter object, or a format string?
585 typedef
586 typename detail::formatter_arity<
587 Format
588 , match_results<BidiIter>
589 , OutputIterator
590 >::type
591 arity;
592
593 return this->format_(out, fmt, flags, arity());
594 }
595
596 /// \overload
597 ///
598 template<typename OutputIterator>
599 OutputIterator format
600 (
601 OutputIterator out
602 , char_type const *fmt
603 , regex_constants::match_flag_type flags = regex_constants::format_default
604 ) const
605 {
606 return this->format_(out, boost::as_literal(fmt), flags, mpl::size_t<0>());
607 }
608
609 /// If \c Format models \c ForwardRange or is a null-terminated string, this function
610 /// returns a copy of the character sequence \c fmt. For each format specifier or escape sequence in \c fmt,
611 /// replace that sequence with either the character(s) it represents, or the sequence within
612 /// <tt>*this</tt> to which it refers. The bitmasks specified in \c flags determines what format specifiers
613 /// or escape sequences are recognized. By default this is the format used by ECMA-262,
614 /// ECMAScript Language Specification, Chapter 15 part 5.4.11 String.prototype.replace.
615 ///
616 /// Otherwise, if \c Format models <tt>Callable\<match_results\<BidiIter\>, OutputIterator, regex_constants::match_flag_type\></tt>,
617 /// this function returns a \c string_type object \c x populated by calling <tt>fmt(*this, out, flags)</tt>,
618 /// where \c out is a \c back_insert_iterator into \c x.
619 ///
620 /// Otherwise, if \c Format models <tt>Callable\<match_results\<BidiIter\>, OutputIterator\></tt>, this function
621 /// returns a \c string_type object \c x populated by calling <tt>fmt(*this, out)</tt>,
622 /// where \c out is a \c back_insert_iterator into \c x.
623 ///
624 /// Otherwise, if \c Format models <tt>Callable\<match_results\<BidiIter\> \></tt>, this function
625 /// returns <tt>fmt(*this)</tt>.
626 template<typename Format, typename OutputIterator>
627 string_type format
628 (
629 Format const &fmt
630 , regex_constants::match_flag_type flags = regex_constants::format_default
631 , typename disable_if<detail::is_char_ptr<Format> >::type * = 0
632 ) const
633 {
634 string_type result;
635 this->format(std::back_inserter(result), fmt, flags);
636 return result;
637 }
638
639 /// \overload
640 ///
641 string_type format
642 (
643 char_type const *fmt
644 , regex_constants::match_flag_type flags = regex_constants::format_default
645 ) const
646 {
647 string_type result;
648 this->format(std::back_inserter(result), fmt, flags);
649 return result;
650 }
651
652 /// Swaps the contents of two match_results objects. Guaranteed not to throw.
653 /// \param that The match_results object to swap with.
654 /// \post *this contains the sequence of matched sub-expressions that were in that,
655 /// that contains the sequence of matched sub-expressions that were in *this.
656 /// \throw nothrow
657 void swap(match_results<BidiIter> &that) // throw()
658 {
659 using std::swap;
660 swap(this->regex_id_, that.regex_id_);
661 this->sub_matches_.swap(that.sub_matches_);
662 this->base_.swap(that.base_);
663 this->prefix_.swap(that.prefix_);
664 this->suffix_.swap(that.suffix_);
665 this->nested_results_.swap(that.nested_results_);
666 this->extras_ptr_.swap(that.extras_ptr_);
667 this->traits_.swap(that.traits_);
668 this->args_.swap(that.args_);
669 }
670
671 /// TODO document me
672 ///
673 template<typename Arg>
674 match_results<BidiIter> &let(Arg const &arg)
675 {
676 typedef typename proto::result_of::left<Arg>::type left_type;
677 typedef typename proto::result_of::right<Arg>::type right_type;
678 typedef typename proto::result_of::value<left_type>::type arg_left_type;
679 typedef typename proto::result_of::value<right_type>::type arg_right_type;
680 BOOST_MPL_ASSERT((proto::matches<Arg, detail::ActionArgBinding>));
681 BOOST_MPL_ASSERT((is_same<typename arg_left_type::type, arg_right_type>));
682 this->args_[&typeid(proto::value(proto::left(arg)))] = &proto::value(proto::right(arg));
683 return *this;
684 }
685
686 /// INTERNAL ONLY
687 ///
688 match_results<BidiIter> const &operator ()(regex_id_type regex_id, size_type index = 0) const
689 {
690 // BUGBUG this is linear, make it O(1)
691 static match_results<BidiIter> const s_null;
692
693 regex_id_filter_predicate<BidiIter> pred(regex_id);
694 typename nested_results_type::const_iterator
695 begin = this->nested_results_.begin()
696 , end = this->nested_results_.end()
697 , cur = detail::find_nth_if(begin, end, index, pred);
698
699 return (cur == end) ? s_null : *cur;
700 }
701
702 /// INTERNAL ONLY
703 ///
704 match_results<BidiIter> const &operator ()(basic_regex<BidiIter> const &rex, std::size_t index = 0) const
705 {
706 return (*this)(rex.regex_id(), index);
707 }
708
709private:
710
711 friend struct detail::core_access<BidiIter>;
712 typedef detail::results_extras<BidiIter> extras_type;
713
714 /// INTERNAL ONLY
715 ///
716 void init_
717 (
718 regex_id_type regex_id
719 , intrusive_ptr<detail::traits<char_type> const> const &tr
720 , detail::sub_match_impl<BidiIter> *sub_matches
721 , size_type size
722 , std::vector<detail::named_mark<char_type> > const &named_marks
723 )
724 {
725 this->traits_ = tr;
726 this->regex_id_ = regex_id;
727 this->named_marks_ = named_marks;
728 detail::core_access<BidiIter>::init_sub_match_vector(this->sub_matches_, sub_matches, size);
729 }
730
731 /// INTERNAL ONLY
732 ///
733 extras_type &get_extras_()
734 {
735 if(!this->extras_ptr_)
736 {
737 this->extras_ptr_ = new extras_type;
738 }
739
740 return *this->extras_ptr_;
741 }
742
743 /// INTERNAL ONLY
744 ///
745 void set_prefix_suffix_(BidiIter begin, BidiIter end)
746 {
747 this->base_ = begin;
748 this->prefix_ = sub_match<BidiIter>(begin, this->sub_matches_[ 0 ].first, begin != this->sub_matches_[ 0 ].first);
749 this->suffix_ = sub_match<BidiIter>(this->sub_matches_[ 0 ].second, end, this->sub_matches_[ 0 ].second != end);
750
751 typename nested_results_type::iterator ibegin = this->nested_results_.begin();
752 typename nested_results_type::iterator iend = this->nested_results_.end();
753 for( ; ibegin != iend; ++ibegin )
754 {
755 ibegin->set_prefix_suffix_(begin, end);
756 }
757 }
758
759 /// INTERNAL ONLY
760 ///
761 void reset_()
762 {
763 detail::core_access<BidiIter>::init_sub_match_vector(this->sub_matches_, 0, 0);
764 }
765
766 /// INTERNAL ONLY
767 ///
768 void set_base_(BidiIter base)
769 {
770 this->base_ = base;
771
772 typename nested_results_type::iterator ibegin = this->nested_results_.begin();
773 typename nested_results_type::iterator iend = this->nested_results_.end();
774 for( ; ibegin != iend; ++ibegin )
775 {
776 ibegin->set_base_(base);
777 }
778 }
779
780 /// INTERNAL ONLY
781 ///
782 const_reference at_(size_type sub) const
783 {
784 return this->sub_matches_[ sub ];
785 }
786
787 /// INTERNAL ONLY
788 ///
789 const_reference at_(detail::basic_mark_tag const &mark) const
790 {
791 return this->sub_matches_[ detail::get_mark_number(mark) ];
792 }
793
794 /// INTERNAL ONLY
795 ///
796 const_reference at_(char_type const *name) const
797 {
798 for(std::size_t i = 0; i < this->named_marks_.size(); ++i)
799 {
800 if(this->named_marks_[i].name_ == name)
801 {
802 return this->sub_matches_[ this->named_marks_[i].mark_nbr_ ];
803 }
804 }
805 BOOST_THROW_EXCEPTION(
806 regex_error(regex_constants::error_badmark, "invalid named back-reference")
807 );
808 // Should never execute, but if it does, this returns
809 // a "null" sub_match.
810 return this->sub_matches_[this->sub_matches_.size()];
811 }
812
813 /// INTERNAL ONLY
814 ///
815 const_reference at_(string_type const &name) const
816 {
817 return (*this)[name.c_str()];
818 }
819
820 /// INTERNAL ONLY
821 ///
822 template<typename OutputIterator, typename ForwardRange>
823 OutputIterator format2_(OutputIterator out, ForwardRange const &result) const
824 {
825 return std::copy(boost::begin(result), boost::end(result), out);
826 }
827
828 /// INTERNAL ONLY
829 ///
830 template<typename OutputIterator, typename Char>
831 OutputIterator format2_(OutputIterator out, Char const *const &result) const
832 {
833 Char const *tmp = result;
834 BOOST_ASSERT(0 != tmp);
835 for(; 0 != *tmp; ++tmp, ++out)
836 {
837 *out = *tmp;
838 }
839 return out;
840 }
841
842 /// INTERNAL ONLY
843 ///
844 template<typename OutputIterator, typename ForwardRange>
845 OutputIterator format_
846 (
847 OutputIterator out
848 , ForwardRange const &format
849 , regex_constants::match_flag_type flags
850 , mpl::size_t<0>
851 ) const
852 {
853 typedef typename range_const_iterator<ForwardRange>::type iterator;
854 iterator cur = boost::begin(format), end = boost::end(format);
855
856 if(0 != (regex_constants::format_literal & flags))
857 {
858 return std::copy(cur, end, out);
859 }
860 else if(0 != (regex_constants::format_perl & flags))
861 {
862 return this->format_perl_(cur, end, out);
863 }
864 else if(0 != (regex_constants::format_sed & flags))
865 {
866 return this->format_sed_(cur, end, out);
867 }
868 else if(0 != (regex_constants::format_all & flags))
869 {
870 return this->format_all_(cur, end, out);
871 }
872
873 return this->format_ecma_262_(cur, end, out);
874 }
875
876 /// INTERNAL ONLY
877 ///
878 template<typename OutputIterator, typename Callable1>
879 OutputIterator format_
880 (
881 OutputIterator out
882 , Callable1 const &format
883 , regex_constants::match_flag_type
884 , mpl::size_t<1>
885 ) const
886 {
887 #if BOOST_WORKAROUND(__GNUC__, == 4) && (__GNUC_MINOR__ == 0)
888 return this->format2_(out, detail::as_callable(format)(*this));
889 #else
890 return this->format2_(out, format(*this));
891 #endif
892 }
893
894 /// INTERNAL ONLY
895 ///
896 template<typename OutputIterator, typename Callable2>
897 OutputIterator format_
898 (
899 OutputIterator out
900 , Callable2 const &format
901 , regex_constants::match_flag_type
902 , mpl::size_t<2>
903 ) const
904 {
905 #if BOOST_WORKAROUND(__GNUC__, == 4) && (__GNUC_MINOR__ == 0)
906 return detail::as_callable(format)(*this, out);
907 #else
908 return format(*this, out);
909 #endif
910 }
911
912 /// INTERNAL ONLY
913 ///
914 template<typename OutputIterator, typename Callable3>
915 OutputIterator format_
916 (
917 OutputIterator out
918 , Callable3 const &format
919 , regex_constants::match_flag_type flags
920 , mpl::size_t<3>
921 ) const
922 {
923 #if BOOST_WORKAROUND(__GNUC__, == 4) && (__GNUC_MINOR__ == 0)
924 return detail::as_callable(format)(*this, out, flags);
925 #else
926 return format(*this, out, flags);
927 #endif
928 }
929
930 /// INTERNAL ONLY
931 ///
932 template<typename OutputIterator, typename Expr>
933 OutputIterator format_
934 (
935 OutputIterator out
936 , Expr const &format
937 , regex_constants::match_flag_type
938 , mpl::size_t<4>
939 ) const
940 {
941 // detail::ReplaceAlgo may be an incomplete type at this point, so
942 // we can't construct it directly.
943 typedef typename mpl::if_c<true, detail::ReplaceAlgo, OutputIterator>::type ReplaceAlgo;
944 return this->format2_(out, ReplaceAlgo()(format, 0, *this));
945 }
946
947 /// INTERNAL ONLY
948 ///
949 template<typename ForwardIterator, typename OutputIterator>
950 OutputIterator format_ecma_262_(ForwardIterator cur, ForwardIterator end, OutputIterator out) const
951 {
952 while(cur != end)
953 {
954 switch(*cur)
955 {
956 case BOOST_XPR_CHAR_(char_type, '$'):
957 out = this->format_backref_(++cur, end, out);
958 break;
959
960 default:
961 *out++ = *cur++;
962 break;
963 }
964 }
965
966 return out;
967 }
968
969 /// INTERNAL ONLY
970 ///
971 template<typename ForwardIterator, typename OutputIterator>
972 OutputIterator format_sed_(ForwardIterator cur, ForwardIterator end, OutputIterator out) const
973 {
974 while(cur != end)
975 {
976 switch(*cur)
977 {
978 case BOOST_XPR_CHAR_(char_type, '&'):
979 ++cur;
980 out = std::copy(this->sub_matches_[ 0 ].first, this->sub_matches_[ 0 ].second, out);
981 break;
982
983 case BOOST_XPR_CHAR_(char_type, '\\'):
984 out = this->format_escape_(++cur, end, out);
985 break;
986
987 default:
988 *out++ = *cur++;
989 break;
990 }
991 }
992
993 return out;
994 }
995
996 /// INTERNAL ONLY
997 ///
998 template<typename ForwardIterator, typename OutputIterator>
999 OutputIterator format_perl_(ForwardIterator cur, ForwardIterator end, OutputIterator out) const
1000 {
1001 detail::case_converting_iterator<OutputIterator, char_type> iout(out, this->traits_.get());
1002
1003 while(cur != end)
1004 {
1005 switch(*cur)
1006 {
1007 case BOOST_XPR_CHAR_(char_type, '$'):
1008 iout = this->format_backref_(++cur, end, iout);
1009 break;
1010
1011 case BOOST_XPR_CHAR_(char_type, '\\'):
1012 if(++cur != end && BOOST_XPR_CHAR_(char_type, 'g') == *cur)
1013 {
1014 iout = this->format_named_backref_(++cur, end, iout);
1015 }
1016 else
1017 {
1018 iout = this->format_escape_(cur, end, iout);
1019 }
1020 break;
1021
1022 default:
1023 *iout++ = *cur++;
1024 break;
1025 }
1026 }
1027
1028 return iout.base();
1029 }
1030
1031 /// INTERNAL ONLY
1032 ///
1033 template<typename ForwardIterator, typename OutputIterator>
1034 OutputIterator format_all_(ForwardIterator cur, ForwardIterator end, OutputIterator out) const
1035 {
1036 detail::case_converting_iterator<OutputIterator, char_type> iout(out, this->traits_.get());
1037 iout = this->format_all_impl_(cur, end, iout);
1038 BOOST_XPR_ENSURE_(cur == end
1039 , regex_constants::error_paren, "unbalanced parentheses in format string");
1040 return iout.base();
1041 }
1042
1043 /// INTERNAL ONLY
1044 ///
1045 template<typename ForwardIterator, typename OutputIterator>
1046 OutputIterator format_all_impl_(ForwardIterator &cur, ForwardIterator end, OutputIterator out, bool metacolon = false) const
1047 {
1048 int max = 0, sub = 0;
1049 detail::noop_output_iterator<char_type> noop;
1050
1051 while(cur != end)
1052 {
1053 switch(*cur)
1054 {
1055 case BOOST_XPR_CHAR_(char_type, '$'):
1056 out = this->format_backref_(++cur, end, out);
1057 break;
1058
1059 case BOOST_XPR_CHAR_(char_type, '\\'):
1060 if(++cur != end && BOOST_XPR_CHAR_(char_type, 'g') == *cur)
1061 {
1062 out = this->format_named_backref_(++cur, end, out);
1063 }
1064 else
1065 {
1066 out = this->format_escape_(cur, end, out);
1067 }
1068 break;
1069
1070 case BOOST_XPR_CHAR_(char_type, '('):
1071 out = this->format_all_impl_(++cur, end, out);
1072 BOOST_XPR_ENSURE_(BOOST_XPR_CHAR_(char_type, ')') == *(cur-1)
1073 , regex_constants::error_paren, "unbalanced parentheses in format string");
1074 break;
1075
1076 case BOOST_XPR_CHAR_(char_type, '?'):
1077 BOOST_XPR_ENSURE_(++cur != end
1078 , regex_constants::error_subreg, "malformed conditional in format string");
1079 max = static_cast<int>(this->size() - 1);
1080 sub = detail::toi(cur, end, *this->traits_, 10, max);
1081 BOOST_XPR_ENSURE_(0 != sub, regex_constants::error_subreg, "invalid back-reference");
1082 if(this->sub_matches_[ sub ].matched)
1083 {
1084 out = this->format_all_impl_(cur, end, out, true);
1085 if(BOOST_XPR_CHAR_(char_type, ':') == *(cur-1))
1086 this->format_all_impl_(cur, end, noop);
1087 }
1088 else
1089 {
1090 this->format_all_impl_(cur, end, noop, true);
1091 if(BOOST_XPR_CHAR_(char_type, ':') == *(cur-1))
1092 out = this->format_all_impl_(cur, end, out);
1093 }
1094 return out;
1095
1096 case BOOST_XPR_CHAR_(char_type, ':'):
1097 if(metacolon)
1098 {
1099 BOOST_FALLTHROUGH;
1100 case BOOST_XPR_CHAR_(char_type, ')'):
1101 ++cur;
1102 return out;
1103 }
1104 BOOST_FALLTHROUGH;
1105
1106 default:
1107 *out++ = *cur++;
1108 break;
1109 }
1110 }
1111
1112 return out;
1113 }
1114
1115 /// INTERNAL ONLY
1116 ///
1117 template<typename ForwardIterator, typename OutputIterator>
1118 OutputIterator format_backref_
1119 (
1120 ForwardIterator &cur
1121 , ForwardIterator end
1122 , OutputIterator out
1123 ) const
1124 {
1125 if(cur == end)
1126 {
1127 *out++ = BOOST_XPR_CHAR_(char_type, '$');
1128 }
1129 else if(BOOST_XPR_CHAR_(char_type, '$') == *cur)
1130 {
1131 *out++ = *cur++;
1132 }
1133 else if(BOOST_XPR_CHAR_(char_type, '&') == *cur) // whole match
1134 {
1135 ++cur;
1136 out = std::copy(this->sub_matches_[ 0 ].first, this->sub_matches_[ 0 ].second, out);
1137 }
1138 else if(BOOST_XPR_CHAR_(char_type, '`') == *cur) // prefix
1139 {
1140 ++cur;
1141 out = std::copy(this->prefix().first, this->prefix().second, out);
1142 }
1143 else if(BOOST_XPR_CHAR_(char_type, '\'') == *cur) // suffix
1144 {
1145 ++cur;
1146 out = std::copy(this->suffix().first, this->suffix().second, out);
1147 }
1148 else if(-1 != this->traits_->value(*cur, 10)) // a sub-match
1149 {
1150 int max = static_cast<int>(this->size() - 1);
1151 int sub = detail::toi(cur, end, *this->traits_, 10, max);
1152 BOOST_XPR_ENSURE_(0 != sub, regex_constants::error_subreg, "invalid back-reference");
1153 if(this->sub_matches_[ sub ].matched)
1154 out = std::copy(this->sub_matches_[ sub ].first, this->sub_matches_[ sub ].second, out);
1155 }
1156 else
1157 {
1158 *out++ = BOOST_XPR_CHAR_(char_type, '$');
1159 *out++ = *cur++;
1160 }
1161
1162 return out;
1163 }
1164
1165 /// INTERNAL ONLY
1166 ///
1167 template<typename ForwardIterator, typename OutputIterator>
1168 OutputIterator format_escape_
1169 (
1170 ForwardIterator &cur
1171 , ForwardIterator end
1172 , OutputIterator out
1173 ) const
1174 {
1175 using namespace regex_constants;
1176 ForwardIterator tmp;
1177 // define an unsigned type the same size as char_type
1178 typedef typename boost::uint_t<CHAR_BIT * sizeof(char_type)>::least uchar_t;
1179 BOOST_MPL_ASSERT_RELATION(sizeof(uchar_t), ==, sizeof(char_type));
1180 typedef numeric::conversion_traits<uchar_t, int> converstion_traits;
1181 numeric::converter<int, uchar_t, converstion_traits, detail::char_overflow_handler_> converter;
1182
1183 if(cur == end)
1184 {
1185 *out++ = BOOST_XPR_CHAR_(char_type, '\\');
1186 return out;
1187 }
1188
1189 char_type ch = *cur++;
1190 switch(ch)
1191 {
1192 case BOOST_XPR_CHAR_(char_type, 'a'):
1193 *out++ = BOOST_XPR_CHAR_(char_type, '\a');
1194 break;
1195
1196 case BOOST_XPR_CHAR_(char_type, 'e'):
1197 *out++ = converter(27);
1198 break;
1199
1200 case BOOST_XPR_CHAR_(char_type, 'f'):
1201 *out++ = BOOST_XPR_CHAR_(char_type, '\f');
1202 break;
1203
1204 case BOOST_XPR_CHAR_(char_type, 'n'):
1205 *out++ = BOOST_XPR_CHAR_(char_type, '\n');
1206 break;
1207
1208 case BOOST_XPR_CHAR_(char_type, 'r'):
1209 *out++ = BOOST_XPR_CHAR_(char_type, '\r');
1210 break;
1211
1212 case BOOST_XPR_CHAR_(char_type, 't'):
1213 *out++ = BOOST_XPR_CHAR_(char_type, '\t');
1214 break;
1215
1216 case BOOST_XPR_CHAR_(char_type, 'v'):
1217 *out++ = BOOST_XPR_CHAR_(char_type, '\v');
1218 break;
1219
1220 case BOOST_XPR_CHAR_(char_type, 'x'):
1221 BOOST_XPR_ENSURE_(cur != end, error_escape, "unexpected end of format found");
1222 if(BOOST_XPR_CHAR_(char_type, '{') == *cur)
1223 {
1224 BOOST_XPR_ENSURE_(++cur != end, error_escape, "unexpected end of format found");
1225 tmp = cur;
1226 *out++ = converter(detail::toi(cur, end, *this->traits_, 16, 0xffff));
1227 BOOST_XPR_ENSURE_(4 == std::distance(tmp, cur) && cur != end && BOOST_XPR_CHAR_(char_type, '}') == *cur++
1228 , error_escape, "invalid hex escape : must be \\x { HexDigit HexDigit HexDigit HexDigit }");
1229 }
1230 else
1231 {
1232 tmp = cur;
1233 *out++ = converter(detail::toi(cur, end, *this->traits_, 16, 0xff));
1234 BOOST_XPR_ENSURE_(2 == std::distance(tmp, cur), error_escape
1235 , "invalid hex escape : must be \\x HexDigit HexDigit");
1236 }
1237 break;
1238
1239 case BOOST_XPR_CHAR_(char_type, 'c'):
1240 BOOST_XPR_ENSURE_(cur != end, error_escape, "unexpected end of format found");
1241 BOOST_XPR_ENSURE_
1242 (
1243 this->traits_->in_range(BOOST_XPR_CHAR_(char_type, 'a'), BOOST_XPR_CHAR_(char_type, 'z'), *cur)
1244 || this->traits_->in_range(BOOST_XPR_CHAR_(char_type, 'A'), BOOST_XPR_CHAR_(char_type, 'Z'), *cur)
1245 , error_escape
1246 , "invalid escape control letter; must be one of a-z or A-Z"
1247 );
1248 // Convert to character according to ECMA-262, section 15.10.2.10:
1249 *out++ = converter(*cur % 32);
1250 ++cur;
1251 break;
1252
1253 case BOOST_XPR_CHAR_(char_type, 'l'):
1254 if(!set_transform(out, detail::op_lower, detail::scope_next))
1255 {
1256 *out++ = BOOST_XPR_CHAR_(char_type, 'l');
1257 }
1258 break;
1259
1260 case BOOST_XPR_CHAR_(char_type, 'L'):
1261 if(!set_transform(out, detail::op_lower, detail::scope_rest))
1262 {
1263 *out++ = BOOST_XPR_CHAR_(char_type, 'L');
1264 }
1265 break;
1266
1267 case BOOST_XPR_CHAR_(char_type, 'u'):
1268 if(!set_transform(out, detail::op_upper, detail::scope_next))
1269 {
1270 *out++ = BOOST_XPR_CHAR_(char_type, 'u');
1271 }
1272 break;
1273
1274 case BOOST_XPR_CHAR_(char_type, 'U'):
1275 if(!set_transform(out, detail::op_upper, detail::scope_rest))
1276 {
1277 *out++ = BOOST_XPR_CHAR_(char_type, 'U');
1278 }
1279 break;
1280
1281 case BOOST_XPR_CHAR_(char_type, 'E'):
1282 if(!set_transform(out, detail::op_none, detail::scope_rest))
1283 {
1284 *out++ = BOOST_XPR_CHAR_(char_type, 'E');
1285 }
1286 break;
1287
1288 default:
1289 // BUGBUG what about backreferences like \12 ?
1290 if(0 < this->traits_->value(ch, 10))
1291 {
1292 int sub = this->traits_->value(ch, 10);
1293 if(this->sub_matches_[ sub ].matched)
1294 out = std::copy(this->sub_matches_[ sub ].first, this->sub_matches_[ sub ].second, out);
1295 }
1296 else
1297 {
1298 *out++ = ch;
1299 }
1300 break;
1301 }
1302
1303 return out;
1304 }
1305
1306 /// INTERNAL ONLY
1307 ///
1308 template<typename ForwardIterator, typename OutputIterator>
1309 OutputIterator format_named_backref_
1310 (
1311 ForwardIterator &cur
1312 , ForwardIterator end
1313 , OutputIterator out
1314 ) const
1315 {
1316 using namespace regex_constants;
1317 BOOST_XPR_ENSURE_(cur != end && BOOST_XPR_CHAR_(char_type, '<') == *cur++
1318 , error_badmark, "invalid named back-reference");
1319 ForwardIterator begin = cur;
1320 for(; cur != end && BOOST_XPR_CHAR_(char_type, '>') != *cur; ++cur)
1321 {}
1322 BOOST_XPR_ENSURE_(cur != begin && cur != end && BOOST_XPR_CHAR_(char_type, '>') == *cur
1323 , error_badmark, "invalid named back-reference");
1324
1325 string_type name(begin, cur++);
1326 for(std::size_t i = 0; i < this->named_marks_.size(); ++i)
1327 {
1328 if(this->named_marks_[i].name_ == name)
1329 {
1330 std::size_t sub = this->named_marks_[i].mark_nbr_;
1331 return std::copy(this->sub_matches_[ sub ].first, this->sub_matches_[ sub ].second, out);
1332 }
1333 }
1334
1335 BOOST_THROW_EXCEPTION(regex_error(error_badmark, "invalid named back-reference"));
1336 // Should never get here
1337 return out;
1338 }
1339
1340 regex_id_type regex_id_;
1341 detail::sub_match_vector<BidiIter> sub_matches_;
1342 boost::optional<BidiIter> base_;
1343 boost::optional<sub_match<BidiIter> > prefix_;
1344 boost::optional<sub_match<BidiIter> > suffix_;
1345 nested_results_type nested_results_;
1346 intrusive_ptr<extras_type> extras_ptr_;
1347 intrusive_ptr<detail::traits<char_type> const> traits_;
1348 detail::action_args_type args_;
1349 std::vector<detail::named_mark<char_type> > named_marks_;
1350};
1351
1352///////////////////////////////////////////////////////////////////////////////
1353// regex_id_filter_predicate
1354//
1355template<typename BidiIter>
1356struct regex_id_filter_predicate
1357 : std::unary_function<match_results<BidiIter>, bool>
1358{
1359 regex_id_filter_predicate(regex_id_type regex_id)
1360 : regex_id_(regex_id)
1361 {
1362 }
1363
1364 bool operator ()(match_results<BidiIter> const &res) const
1365 {
1366 return this->regex_id_ == res.regex_id();
1367 }
1368
1369private:
1370
1371 regex_id_type regex_id_;
1372};
1373
1374}} // namespace boost::xpressive
1375
1376#ifdef BOOST_HAS_CONCEPTS
1377// Better living through concepts. :-P
1378namespace std
1379{
1380 template<typename Iter_, typename Char_>
1381 concept_map OutputIterator<
1382 boost::xpressive::detail::case_converting_iterator<Iter_, Char_>
1383 , Char_
1384 >
1385 {};
1386
1387 template<typename Char_>
1388 concept_map OutputIterator<
1389 boost::xpressive::detail::noop_output_iterator<Char_>
1390 , Char_
1391 >
1392 {};
1393}
1394#endif
1395
1396#endif
1397

source code of boost/boost/xpressive/match_results.hpp