]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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(*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 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 | // | |
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 &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 | ||
709 | private: | |
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 | // | |
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 |