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 | |
67 | namespace boost { namespace xpressive { namespace detail |
68 | { |
69 | |
70 | /////////////////////////////////////////////////////////////////////////////// |
71 | // type_info_less |
72 | // |
73 | struct 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 | // |
84 | struct ActionArgBinding |
85 | : proto::assign<proto::terminal<action_arg<proto::_, proto::_> >, proto::terminal<proto::_> > |
86 | { |
87 | }; |
88 | |
89 | /////////////////////////////////////////////////////////////////////////////// |
90 | // results_extras |
91 | // |
92 | template<typename BidiIter> |
93 | struct |
94 | : counted_base<results_extras<BidiIter> > |
95 | { |
96 | sequence_stack<sub_match_impl<BidiIter> > ; |
97 | results_cache<BidiIter> ; |
98 | }; |
99 | |
100 | /////////////////////////////////////////////////////////////////////////////// |
101 | // char_overflow_handler_ |
102 | // |
103 | struct 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 | // |
122 | enum transform_op { op_none = 0, op_upper = 1, op_lower = 2 }; |
123 | enum transform_scope { scope_next = 0, scope_rest = 1 }; |
124 | |
125 | /////////////////////////////////////////////////////////////////////////////// |
126 | // case_converting_iterator |
127 | // |
128 | template<typename OutputIterator, typename Char> |
129 | struct 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 | |
192 | private: |
193 | OutputIterator out_; |
194 | traits<Char> const *traits_; |
195 | transform_op next_, rest_; |
196 | }; |
197 | |
198 | template<typename Iterator> |
199 | inline bool set_transform(Iterator &, transform_op, transform_scope) |
200 | { |
201 | return false; |
202 | } |
203 | |
204 | /////////////////////////////////////////////////////////////////////////////// |
205 | // noop_output_iterator |
206 | // |
207 | template<typename Char> |
208 | struct 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 | |
232 | struct any_type { any_type(...); }; |
233 | typedef char no_type; |
234 | typedef char (&unary_type)[2]; |
235 | typedef char (&binary_type)[3]; |
236 | typedef char (&ternary_type)[4]; |
237 | |
238 | no_type check_is_formatter(unary_type, binary_type, ternary_type); |
239 | |
240 | template<typename T> |
241 | unary_type check_is_formatter(T const &, binary_type, ternary_type); |
242 | |
243 | template<typename T> |
244 | binary_type check_is_formatter(unary_type, T const &, ternary_type); |
245 | |
246 | template<typename T, typename U> |
247 | binary_type check_is_formatter(T const &, U const &, ternary_type); |
248 | |
249 | template<typename T> |
250 | ternary_type check_is_formatter(unary_type, binary_type, T const &); |
251 | |
252 | template<typename T, typename U> |
253 | ternary_type check_is_formatter(T const &, binary_type, U const &); |
254 | |
255 | template<typename T, typename U> |
256 | ternary_type check_is_formatter(unary_type, T const &, U const &); |
257 | |
258 | template<typename T, typename U, typename V> |
259 | ternary_type check_is_formatter(T const &, U const &, V const &); |
260 | |
261 | struct 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 | |
271 | template<typename Formatter, bool IsFunction = is_function<Formatter>::value> |
272 | struct formatter_wrapper |
273 | : Formatter |
274 | , unary_binary_ternary |
275 | { |
276 | formatter_wrapper(); |
277 | }; |
278 | |
279 | template<typename Formatter> |
280 | struct formatter_wrapper<Formatter, true> |
281 | : unary_binary_ternary |
282 | { |
283 | operator Formatter *(); |
284 | }; |
285 | |
286 | template<typename Formatter> |
287 | struct formatter_wrapper<Formatter *, false> |
288 | : unary_binary_ternary |
289 | { |
290 | operator Formatter *(); |
291 | }; |
292 | |
293 | template<typename Formatter, typename What, typename Out, typename Void = void> |
294 | struct 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 | |
312 | template<typename Formatter, typename What, typename Out> |
313 | struct formatter_arity<Formatter, What, Out, typename Formatter::proto_is_expr_> |
314 | : mpl::size_t<4> |
315 | {}; |
316 | |
317 | template<typename T> |
318 | struct is_char_ptr |
319 | : mpl::false_ |
320 | {}; |
321 | |
322 | template<typename T> |
323 | struct 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 |
329 | template<typename T> |
330 | typename mpl::if_<is_function<T>, T *, T const &>::type |
331 | as_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. |
351 | template<typename BidiIter> |
352 | struct match_results |
353 | { |
354 | private: |
355 | /// INTERNAL ONLY |
356 | /// |
357 | struct dummy { int i_; }; |
358 | typedef int dummy::*bool_type; |
359 | |
360 | public: |
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 & = 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 | |
709 | private: |
710 | |
711 | friend struct detail::core_access<BidiIter>; |
712 | typedef detail::results_extras<BidiIter> ; |
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 &() |
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> ; |
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 | // |
1355 | template<typename BidiIter> |
1356 | struct 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 | |
1369 | private: |
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 |
1378 | namespace 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 | |