Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: /// \file match_results.hpp Chris@16: /// Contains the definition of the match_results type and associated helpers. Chris@16: /// The match_results type holds the results of a regex_match() or Chris@16: /// regex_search() operation. Chris@16: // Chris@16: // Copyright 2008 Eric Niebler. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: // Acknowledgements: Thanks to Markus Schoepflin for helping to track down Chris@16: // a tricky formatting bug on HP Tru64, and to Steven Watanabe for suggesting Chris@16: // the fix. Chris@16: Chris@16: #ifndef BOOST_XPRESSIVE_MATCH_RESULTS_HPP_EAN_10_04_2005 Chris@16: #define BOOST_XPRESSIVE_MATCH_RESULTS_HPP_EAN_10_04_2005 Chris@16: Chris@16: // MS compatible compilers support #pragma once Chris@101: #if defined(_MSC_VER) Chris@16: # pragma once Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #if BOOST_ITERATOR_ADAPTORS_VERSION >= 0x0200 Chris@16: # include Chris@16: #endif Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: // Doxygen can't handle proto :-( Chris@16: #ifndef BOOST_XPRESSIVE_DOXYGEN_INVOKED Chris@16: # include Chris@16: # include Chris@16: #endif Chris@16: Chris@16: namespace boost { namespace xpressive { namespace detail Chris@16: { Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // type_info_less Chris@16: // Chris@16: struct type_info_less Chris@16: { Chris@16: bool operator()(std::type_info const *left, std::type_info const *right) const Chris@16: { Chris@16: return 0 != left->before(*right); Chris@16: } Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // ActionArgBinding Chris@16: // Chris@16: struct ActionArgBinding Chris@16: : proto::assign >, proto::terminal > Chris@16: { Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // results_extras Chris@16: // Chris@16: template Chris@16: struct results_extras Chris@16: : counted_base > Chris@16: { Chris@16: sequence_stack > sub_match_stack_; Chris@16: results_cache results_cache_; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // char_overflow_handler_ Chris@16: // Chris@16: struct char_overflow_handler_ Chris@16: { Chris@16: void operator ()(numeric::range_check_result result) const // throw(regex_error) Chris@16: { Chris@16: if(numeric::cInRange != result) Chris@16: { Chris@16: BOOST_THROW_EXCEPTION( Chris@16: regex_error( Chris@16: regex_constants::error_escape Chris@16: , "character escape too large to fit in target character type" Chris@16: ) Chris@16: ); Chris@16: } Chris@16: } Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // transform_op enum Chris@16: // Chris@16: enum transform_op { op_none = 0, op_upper = 1, op_lower = 2 }; Chris@16: enum transform_scope { scope_next = 0, scope_rest = 1 }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // case_converting_iterator Chris@16: // Chris@16: template Chris@16: struct case_converting_iterator Chris@16: : std::iterator > Chris@16: { Chris@16: case_converting_iterator(OutputIterator const &out, traits const *tr) Chris@16: : out_(out) Chris@16: , traits_(tr) Chris@16: , next_(op_none) Chris@16: , rest_(op_none) Chris@16: {} Chris@16: Chris@16: OutputIterator base() const Chris@16: { Chris@16: return this->out_; Chris@16: } Chris@16: Chris@16: case_converting_iterator &operator ++() Chris@16: { Chris@16: ++this->out_; Chris@16: this->next_ = op_none; Chris@16: return *this; Chris@16: } Chris@16: Chris@16: case_converting_iterator operator ++(int) Chris@16: { Chris@16: case_converting_iterator tmp(*this); Chris@16: ++*this; Chris@16: return tmp; Chris@16: } Chris@16: Chris@16: case_converting_iterator &operator *() Chris@16: { Chris@16: return *this; Chris@16: } Chris@16: Chris@16: friend bool set_transform(case_converting_iterator &iter, transform_op trans, transform_scope scope) Chris@16: { Chris@16: BOOST_ASSERT(scope == scope_next || scope == scope_rest); Chris@16: if(scope == scope_next) Chris@16: iter.next_ = trans; Chris@16: else Chris@16: iter.rest_ = trans; Chris@16: return true; Chris@16: } Chris@16: Chris@16: case_converting_iterator &operator =(Char ch) Chris@16: { Chris@16: switch(this->next_ ? this->next_ : this->rest_) Chris@16: { Chris@16: case op_lower: Chris@16: ch = this->traits_->tolower(ch); Chris@16: break; Chris@16: Chris@16: case op_upper: Chris@16: ch = this->traits_->toupper(ch); Chris@16: break; Chris@16: Chris@16: default:; Chris@16: } Chris@16: Chris@16: *this->out_ = ch; Chris@16: return *this; Chris@16: } Chris@16: Chris@16: private: Chris@16: OutputIterator out_; Chris@16: traits const *traits_; Chris@16: transform_op next_, rest_; Chris@16: }; Chris@16: Chris@16: template Chris@16: inline bool set_transform(Iterator &, transform_op, transform_scope) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // noop_output_iterator Chris@16: // Chris@16: template Chris@16: struct noop_output_iterator Chris@16: : std::iterator > Chris@16: { Chris@16: noop_output_iterator &operator ++() Chris@16: { Chris@16: return *this; Chris@16: } Chris@16: Chris@16: noop_output_iterator &operator ++(int) Chris@16: { Chris@16: return *this; Chris@16: } Chris@16: Chris@16: noop_output_iterator &operator *() Chris@16: { Chris@16: return *this; Chris@16: } Chris@16: Chris@16: noop_output_iterator &operator =(Char const &) Chris@16: { Chris@16: return *this; Chris@16: } Chris@16: }; Chris@16: Chris@16: struct any_type { any_type(...); }; Chris@16: typedef char no_type; Chris@16: typedef char (&unary_type)[2]; Chris@16: typedef char (&binary_type)[3]; Chris@16: typedef char (&ternary_type)[4]; Chris@16: Chris@16: no_type check_is_formatter(unary_type, binary_type, ternary_type); Chris@16: Chris@16: template Chris@16: unary_type check_is_formatter(T const &, binary_type, ternary_type); Chris@16: Chris@16: template Chris@16: binary_type check_is_formatter(unary_type, T const &, ternary_type); Chris@16: Chris@16: template Chris@16: binary_type check_is_formatter(T const &, U const &, ternary_type); Chris@16: Chris@16: template Chris@16: ternary_type check_is_formatter(unary_type, binary_type, T const &); Chris@16: Chris@16: template Chris@16: ternary_type check_is_formatter(T const &, binary_type, U const &); Chris@16: Chris@16: template Chris@16: ternary_type check_is_formatter(unary_type, T const &, U const &); Chris@16: Chris@16: template Chris@16: ternary_type check_is_formatter(T const &, U const &, V const &); Chris@16: Chris@16: struct unary_binary_ternary Chris@16: { Chris@16: typedef unary_type (*unary_fun)(any_type); Chris@16: typedef binary_type (*binary_fun)(any_type, any_type); Chris@16: typedef ternary_type (*ternary_fun)(any_type, any_type, any_type); Chris@16: operator unary_fun(); Chris@16: operator binary_fun(); Chris@16: operator ternary_fun(); Chris@16: }; Chris@16: Chris@16: template::value> Chris@16: struct formatter_wrapper Chris@16: : Formatter Chris@16: , unary_binary_ternary Chris@16: { Chris@16: formatter_wrapper(); Chris@16: }; Chris@16: Chris@16: template Chris@16: struct formatter_wrapper Chris@16: : unary_binary_ternary Chris@16: { Chris@16: operator Formatter *(); Chris@16: }; Chris@16: Chris@16: template Chris@16: struct formatter_wrapper Chris@16: : unary_binary_ternary Chris@16: { Chris@16: operator Formatter *(); Chris@16: }; Chris@16: Chris@16: template Chris@16: struct formatter_arity Chris@16: { Chris@16: static formatter_wrapper &formatter; Chris@16: static What &what; Chris@16: static Out &out; Chris@16: BOOST_STATIC_CONSTANT( Chris@16: std::size_t Chris@16: , value = sizeof( Chris@16: check_is_formatter( Chris@16: formatter(what) Chris@16: , formatter(what, out) Chris@16: , formatter(what, out, regex_constants::format_default) Chris@16: ) Chris@16: ) - 1 Chris@16: ); Chris@16: typedef mpl::size_t type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct formatter_arity Chris@16: : mpl::size_t<4> Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct is_char_ptr Chris@16: : mpl::false_ Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct is_char_ptr Chris@16: : mpl::not_ > Chris@16: {}; Chris@16: Chris@16: #if BOOST_WORKAROUND(__GNUC__, == 4) && (__GNUC_MINOR__ == 0) Chris@16: // work around gcc-4.0.1 compiler bug wrt function references Chris@16: template Chris@16: typename mpl::if_, T *, T const &>::type Chris@16: as_callable(T const &t) Chris@16: { Chris@16: return t; Chris@16: } Chris@16: #endif Chris@16: Chris@16: } // detail Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // match_results Chris@16: /// \brief Class template match_results\<\> holds the results of a regex_match() or a Chris@16: /// regex_search() as a collection of sub_match objects. Chris@16: /// Chris@16: /// Class template match_results\<\> denotes a collection of sequences representing the result of Chris@16: /// a regular expression match. Storage for the collection is allocated and freed as necessary by Chris@16: /// the member functions of class match_results\<\>. Chris@16: /// Chris@16: /// The class template match_results\<\> conforms to the requirements of a Sequence, as specified Chris@16: /// in (lib.sequence.reqmts), except that only operations defined for const-qualified Sequences are Chris@16: /// supported. Chris@16: template Chris@16: struct match_results Chris@16: { Chris@16: private: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: struct dummy { int i_; }; Chris@16: typedef int dummy::*bool_type; Chris@16: Chris@16: public: Chris@16: typedef typename iterator_value::type char_type; Chris@16: typedef typename detail::string_type::type string_type; Chris@16: typedef std::size_t size_type; Chris@16: typedef sub_match value_type; Chris@16: typedef typename iterator_difference::type difference_type; Chris@16: typedef value_type const &reference; Chris@16: typedef value_type const &const_reference; Chris@16: Chris@16: typedef typename detail::sub_match_vector::iterator iterator; Chris@16: typedef typename detail::sub_match_vector::const_iterator const_iterator; Chris@16: typedef typename detail::nested_results nested_results_type; Chris@16: Chris@16: /// \post regex_id() == 0 Chris@16: /// \post size() == 0 Chris@16: /// \post empty() == true Chris@16: /// \post str() == string_type() Chris@16: match_results() Chris@16: : regex_id_(0) Chris@16: , sub_matches_() Chris@16: , base_() Chris@16: , prefix_() Chris@16: , suffix_() Chris@16: , nested_results_() Chris@16: , extras_ptr_() Chris@16: , traits_() Chris@16: , args_() Chris@16: , named_marks_() Chris@16: { Chris@16: } Chris@16: Chris@16: /// \param that The match_results object to copy Chris@16: /// \post regex_id() == that.regex_id(). Chris@16: /// \post size() == that.size(). Chris@16: /// \post empty() == that.empty(). Chris@16: /// \post str(n) == that.str(n) for all positive integers n \< that.size(). Chris@16: /// \post prefix() == that.prefix(). Chris@16: /// \post suffix() == that.suffix(). Chris@16: /// \post (*this)[n] == that[n] for all positive integers n \< that.size(). Chris@16: /// \post length(n) == that.length(n) for all positive integers n \< that.size(). Chris@16: /// \post position(n) == that.position(n) for all positive integers n \< that.size(). Chris@16: match_results(match_results const &that) Chris@16: : regex_id_(that.regex_id_) Chris@16: , sub_matches_() Chris@16: , base_() Chris@16: , prefix_() Chris@16: , suffix_() Chris@16: , nested_results_() Chris@16: , extras_ptr_() Chris@16: , traits_() Chris@16: , args_(that.args_) Chris@16: , named_marks_(that.named_marks_) Chris@16: { Chris@16: if(that) Chris@16: { Chris@16: extras_type &extras = this->get_extras_(); Chris@16: std::size_t size = that.sub_matches_.size(); Chris@16: detail::sub_match_impl *sub_matches = extras.sub_match_stack_.push_sequence(size, detail::sub_match_impl(*that.base_), detail::fill); Chris@16: detail::core_access::init_sub_match_vector(this->sub_matches_, sub_matches, size, that.sub_matches_); Chris@16: Chris@16: this->base_ = that.base_; Chris@16: this->prefix_ = that.prefix_; Chris@16: this->suffix_ = that.suffix_; Chris@16: // BUGBUG this doesn't share the extras::sequence_stack Chris@16: this->nested_results_ = that.nested_results_; Chris@16: this->traits_ = that.traits_; Chris@16: } Chris@16: } Chris@16: Chris@16: ~match_results() Chris@16: { Chris@16: } Chris@16: Chris@16: /// \param that The match_results object to copy. Chris@16: /// \post regex_id() == that.regex_id(). Chris@16: /// \post size() == that.size(). Chris@16: /// \post empty() == that.empty(). Chris@16: /// \post str(n) == that.str(n) for all positive integers n \< that.size(). Chris@16: /// \post prefix() == that.prefix(). Chris@16: /// \post suffix() == that.suffix(). Chris@16: /// \post (*this)[n] == that[n] for all positive integers n \< that.size(). Chris@16: /// \post length(n) == that.length(n) for all positive integers n \< that.size(). Chris@16: /// \post position(n) == that.position(n) for all positive integers n \< that.size(). Chris@16: match_results &operator =(match_results const &that) Chris@16: { Chris@16: match_results(that).swap(*this); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: /// Returns one plus the number of marked sub-expressions in the regular Chris@16: /// expression that was matched if *this represents the result of a Chris@16: /// successful match. Otherwise returns 0. Chris@16: size_type size() const Chris@16: { Chris@16: return this->sub_matches_.size(); Chris@16: } Chris@16: Chris@16: /// Returns size() == 0. Chris@16: /// Chris@16: bool empty() const Chris@16: { Chris@16: return 0 == this->size(); Chris@16: } Chris@16: Chris@16: /// Returns (*this)[sub].length(). Chris@16: /// Chris@16: difference_type length(size_type sub = 0) const Chris@16: { Chris@16: return this->sub_matches_[ sub ].length(); Chris@16: } Chris@16: Chris@16: /// If !(*this)[sub].matched then returns -1. Otherwise returns std::distance(base, (*this)[sub].first), Chris@16: /// where base is the start iterator of the sequence that was searched. [Note - unless this is part Chris@16: /// of a repeated search with a regex_iterator then base is the same as prefix().first - end note] Chris@16: difference_type position(size_type sub = 0) const Chris@16: { Chris@16: return this->sub_matches_[ sub ].matched ? std::distance(*this->base_, this->sub_matches_[ sub ].first) : -1; Chris@16: } Chris@16: Chris@16: /// Returns (*this)[sub].str(). Chris@16: /// Chris@16: string_type str(size_type sub = 0) const Chris@16: { Chris@16: return this->sub_matches_[ sub ].str(); Chris@16: } Chris@16: Chris@16: /// Returns a reference to the sub_match object representing the sequence that Chris@16: /// matched marked sub-expression sub. If sub == 0 then returns a reference to Chris@16: /// a sub_match object representing the sequence that matched the whole regular Chris@16: /// expression. If sub >= size() then returns a sub_match object representing an Chris@16: /// unmatched sub-expression. Chris@16: template Chris@16: const_reference operator [](Sub const &sub) const Chris@16: { Chris@16: return this->at_(sub); Chris@16: } Chris@16: Chris@16: /// Returns a reference to the sub_match object representing the character sequence from Chris@16: /// the start of the string being matched/searched, to the start of the match found. Chris@16: /// Chris@16: /// \pre (*this)[0].matched is true Chris@16: const_reference prefix() const Chris@16: { Chris@16: return this->prefix_ ? *this->prefix_ : this->sub_matches_[this->sub_matches_.size()]; Chris@16: } Chris@16: Chris@16: /// Returns a reference to the sub_match object representing the character sequence from Chris@16: /// the end of the match found to the end of the string being matched/searched. Chris@16: /// Chris@16: /// \pre (*this)[0].matched is true Chris@16: const_reference suffix() const Chris@16: { Chris@16: return this->suffix_ ? *this->suffix_ : this->sub_matches_[this->sub_matches_.size()]; Chris@16: } Chris@16: Chris@16: /// Returns a starting iterator that enumerates over all the marked sub-expression matches Chris@16: /// stored in *this. Chris@16: /// Chris@16: const_iterator begin() const Chris@16: { Chris@16: return this->sub_matches_.begin(); Chris@16: } Chris@16: Chris@16: /// Returns a terminating iterator that enumerates over all the marked sub-expression Chris@16: /// matches stored in *this. Chris@16: /// Chris@16: const_iterator end() const Chris@16: { Chris@16: return this->sub_matches_.end(); Chris@16: } Chris@16: Chris@16: /// Returns a true value if (*this)[0].matched, else returns a false value. Chris@16: /// Chris@16: operator bool_type() const Chris@16: { Chris@16: return (!this->empty() && this->sub_matches_[ 0 ].matched) ? &dummy::i_ : 0; Chris@16: } Chris@16: Chris@16: /// Returns true if empty() || !(*this)[0].matched, else returns false. Chris@16: /// Chris@16: bool operator !() const Chris@16: { Chris@16: return this->empty() || !this->sub_matches_[ 0 ].matched; Chris@16: } Chris@16: Chris@16: /// Returns the id of the basic_regex object most recently used with this match_results object. Chris@16: /// Chris@16: regex_id_type regex_id() const Chris@16: { Chris@16: return this->regex_id_; Chris@16: } Chris@16: Chris@16: /// Returns a Sequence of nested match_results elements. Chris@16: /// Chris@16: nested_results_type const &nested_results() const Chris@16: { Chris@16: return this->nested_results_; Chris@16: } Chris@16: Chris@16: /// If \c Format models \c ForwardRange or is a null-terminated string, this function Chris@16: /// copies the character sequence in \c fmt to \c OutputIterator \c out. For each format Chris@16: /// specifier or escape sequence in \c fmt, replace that sequence with either the character(s) it Chris@16: /// represents, or the sequence within *this to which it refers. The bitmasks specified in flags Chris@16: /// determines what format specifiers or escape sequences are recognized. By default, this is the Chris@16: /// format used by ECMA-262, ECMAScript Language Specification, Chapter 15 part 5.4.11 String.prototype.replace. Chris@16: /// Chris@16: /// Otherwise, if \c Format models Callable\, OutputIterator, regex_constants::match_flag_type\>, Chris@16: /// this function returns fmt(*this, out, flags). Chris@16: /// Chris@16: /// Otherwise, if \c Format models Callable\, OutputIterator\>, this function Chris@16: /// returns fmt(*this, out). Chris@16: /// Chris@16: /// Otherwise, if \c Format models Callable\ \>, this function Chris@16: /// returns std::copy(x.begin(), x.end(), out), where \c x is the result of Chris@16: /// calling fmt(*this). Chris@16: template Chris@16: OutputIterator format Chris@16: ( Chris@16: OutputIterator out Chris@16: , Format const &fmt Chris@16: , regex_constants::match_flag_type flags = regex_constants::format_default Chris@16: , typename disable_if >::type * = 0 Chris@16: ) const Chris@16: { Chris@16: // Is this a formatter object, or a format string? Chris@16: typedef Chris@16: typename detail::formatter_arity< Chris@16: Format Chris@16: , match_results Chris@16: , OutputIterator Chris@16: >::type Chris@16: arity; Chris@16: Chris@16: return this->format_(out, fmt, flags, arity()); Chris@16: } Chris@16: Chris@16: /// \overload Chris@16: /// Chris@16: template Chris@16: OutputIterator format Chris@16: ( Chris@16: OutputIterator out Chris@16: , char_type const *fmt Chris@16: , regex_constants::match_flag_type flags = regex_constants::format_default Chris@16: ) const Chris@16: { Chris@16: return this->format_(out, boost::as_literal(fmt), flags, mpl::size_t<0>()); Chris@16: } Chris@16: Chris@16: /// If \c Format models \c ForwardRange or is a null-terminated string, this function Chris@16: /// returns a copy of the character sequence \c fmt. For each format specifier or escape sequence in \c fmt, Chris@16: /// replace that sequence with either the character(s) it represents, or the sequence within Chris@16: /// *this to which it refers. The bitmasks specified in \c flags determines what format specifiers Chris@16: /// or escape sequences are recognized. By default this is the format used by ECMA-262, Chris@16: /// ECMAScript Language Specification, Chapter 15 part 5.4.11 String.prototype.replace. Chris@16: /// Chris@16: /// Otherwise, if \c Format models Callable\, OutputIterator, regex_constants::match_flag_type\>, Chris@16: /// this function returns a \c string_type object \c x populated by calling fmt(*this, out, flags), Chris@16: /// where \c out is a \c back_insert_iterator into \c x. Chris@16: /// Chris@16: /// Otherwise, if \c Format models Callable\, OutputIterator\>, this function Chris@16: /// returns a \c string_type object \c x populated by calling fmt(*this, out), Chris@16: /// where \c out is a \c back_insert_iterator into \c x. Chris@16: /// Chris@16: /// Otherwise, if \c Format models Callable\ \>, this function Chris@16: /// returns fmt(*this). Chris@16: template Chris@16: string_type format Chris@16: ( Chris@16: Format const &fmt Chris@16: , regex_constants::match_flag_type flags = regex_constants::format_default Chris@16: , typename disable_if >::type * = 0 Chris@16: ) const Chris@16: { Chris@16: string_type result; Chris@16: this->format(std::back_inserter(result), fmt, flags); Chris@16: return result; Chris@16: } Chris@16: Chris@16: /// \overload Chris@16: /// Chris@16: string_type format Chris@16: ( Chris@16: char_type const *fmt Chris@16: , regex_constants::match_flag_type flags = regex_constants::format_default Chris@16: ) const Chris@16: { Chris@16: string_type result; Chris@16: this->format(std::back_inserter(result), fmt, flags); Chris@16: return result; Chris@16: } Chris@16: Chris@16: /// Swaps the contents of two match_results objects. Guaranteed not to throw. Chris@16: /// \param that The match_results object to swap with. Chris@16: /// \post *this contains the sequence of matched sub-expressions that were in that, Chris@16: /// that contains the sequence of matched sub-expressions that were in *this. Chris@16: /// \throw nothrow Chris@16: void swap(match_results &that) // throw() Chris@16: { Chris@16: using std::swap; Chris@16: swap(this->regex_id_, that.regex_id_); Chris@16: this->sub_matches_.swap(that.sub_matches_); Chris@16: this->base_.swap(that.base_); Chris@16: this->prefix_.swap(that.prefix_); Chris@16: this->suffix_.swap(that.suffix_); Chris@16: this->nested_results_.swap(that.nested_results_); Chris@16: this->extras_ptr_.swap(that.extras_ptr_); Chris@16: this->traits_.swap(that.traits_); Chris@16: this->args_.swap(that.args_); Chris@16: } Chris@16: Chris@16: /// TODO document me Chris@16: /// Chris@16: template Chris@16: match_results &let(Arg const &arg) Chris@16: { Chris@16: typedef typename proto::result_of::left::type left_type; Chris@16: typedef typename proto::result_of::right::type right_type; Chris@16: typedef typename proto::result_of::value::type arg_left_type; Chris@16: typedef typename proto::result_of::value::type arg_right_type; Chris@16: BOOST_MPL_ASSERT((proto::matches)); Chris@16: BOOST_MPL_ASSERT((is_same)); Chris@16: this->args_[&typeid(proto::value(proto::left(arg)))] = &proto::value(proto::right(arg)); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: match_results const &operator ()(regex_id_type regex_id, size_type index = 0) const Chris@16: { Chris@16: // BUGBUG this is linear, make it O(1) Chris@16: static match_results const s_null; Chris@16: Chris@16: regex_id_filter_predicate pred(regex_id); Chris@16: typename nested_results_type::const_iterator Chris@16: begin = this->nested_results_.begin() Chris@16: , end = this->nested_results_.end() Chris@16: , cur = detail::find_nth_if(begin, end, index, pred); Chris@16: Chris@16: return (cur == end) ? s_null : *cur; Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: match_results const &operator ()(basic_regex const &rex, std::size_t index = 0) const Chris@16: { Chris@16: return (*this)(rex.regex_id(), index); Chris@16: } Chris@16: Chris@16: private: Chris@16: Chris@16: friend struct detail::core_access; Chris@16: typedef detail::results_extras extras_type; Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: void init_ Chris@16: ( Chris@16: regex_id_type regex_id Chris@16: , intrusive_ptr const> const &tr Chris@16: , detail::sub_match_impl *sub_matches Chris@16: , size_type size Chris@16: , std::vector > const &named_marks Chris@16: ) Chris@16: { Chris@16: this->traits_ = tr; Chris@16: this->regex_id_ = regex_id; Chris@16: this->named_marks_ = named_marks; Chris@16: detail::core_access::init_sub_match_vector(this->sub_matches_, sub_matches, size); Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: extras_type &get_extras_() Chris@16: { Chris@16: if(!this->extras_ptr_) Chris@16: { Chris@16: this->extras_ptr_ = new extras_type; Chris@16: } Chris@16: Chris@16: return *this->extras_ptr_; Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: void set_prefix_suffix_(BidiIter begin, BidiIter end) Chris@16: { Chris@16: this->base_ = begin; Chris@16: this->prefix_ = sub_match(begin, this->sub_matches_[ 0 ].first, begin != this->sub_matches_[ 0 ].first); Chris@16: this->suffix_ = sub_match(this->sub_matches_[ 0 ].second, end, this->sub_matches_[ 0 ].second != end); Chris@16: Chris@16: typename nested_results_type::iterator ibegin = this->nested_results_.begin(); Chris@16: typename nested_results_type::iterator iend = this->nested_results_.end(); Chris@16: for( ; ibegin != iend; ++ibegin ) Chris@16: { Chris@16: ibegin->set_prefix_suffix_(begin, end); Chris@16: } Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: void reset_() Chris@16: { Chris@16: detail::core_access::init_sub_match_vector(this->sub_matches_, 0, 0); Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: void set_base_(BidiIter base) Chris@16: { Chris@16: this->base_ = base; Chris@16: Chris@16: typename nested_results_type::iterator ibegin = this->nested_results_.begin(); Chris@16: typename nested_results_type::iterator iend = this->nested_results_.end(); Chris@16: for( ; ibegin != iend; ++ibegin ) Chris@16: { Chris@16: ibegin->set_base_(base); Chris@16: } Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: const_reference at_(size_type sub) const Chris@16: { Chris@16: return this->sub_matches_[ sub ]; Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: const_reference at_(detail::basic_mark_tag const &mark) const Chris@16: { Chris@16: return this->sub_matches_[ detail::get_mark_number(mark) ]; Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: const_reference at_(char_type const *name) const Chris@16: { Chris@16: for(std::size_t i = 0; i < this->named_marks_.size(); ++i) Chris@16: { Chris@16: if(this->named_marks_[i].name_ == name) Chris@16: { Chris@16: return this->sub_matches_[ this->named_marks_[i].mark_nbr_ ]; Chris@16: } Chris@16: } Chris@16: BOOST_THROW_EXCEPTION( Chris@16: regex_error(regex_constants::error_badmark, "invalid named back-reference") Chris@16: ); Chris@16: // Should never execute, but if it does, this returns Chris@16: // a "null" sub_match. Chris@16: return this->sub_matches_[this->sub_matches_.size()]; Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: const_reference at_(string_type const &name) const Chris@16: { Chris@16: return (*this)[name.c_str()]; Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: OutputIterator format2_(OutputIterator out, ForwardRange const &result) const Chris@16: { Chris@16: return std::copy(boost::begin(result), boost::end(result), out); Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: OutputIterator format2_(OutputIterator out, Char const *const &result) const Chris@16: { Chris@16: Char const *tmp = result; Chris@16: BOOST_ASSERT(0 != tmp); Chris@16: for(; 0 != *tmp; ++tmp, ++out) Chris@16: { Chris@16: *out = *tmp; Chris@16: } Chris@16: return out; Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: OutputIterator format_ Chris@16: ( Chris@16: OutputIterator out Chris@16: , ForwardRange const &format Chris@16: , regex_constants::match_flag_type flags Chris@16: , mpl::size_t<0> Chris@16: ) const Chris@16: { Chris@16: typedef typename range_const_iterator::type iterator; Chris@16: iterator cur = boost::begin(format), end = boost::end(format); Chris@16: Chris@16: if(0 != (regex_constants::format_literal & flags)) Chris@16: { Chris@16: return std::copy(cur, end, out); Chris@16: } Chris@16: else if(0 != (regex_constants::format_perl & flags)) Chris@16: { Chris@16: return this->format_perl_(cur, end, out); Chris@16: } Chris@16: else if(0 != (regex_constants::format_sed & flags)) Chris@16: { Chris@16: return this->format_sed_(cur, end, out); Chris@16: } Chris@16: else if(0 != (regex_constants::format_all & flags)) Chris@16: { Chris@16: return this->format_all_(cur, end, out); Chris@16: } Chris@16: Chris@16: return this->format_ecma_262_(cur, end, out); Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: OutputIterator format_ Chris@16: ( Chris@16: OutputIterator out Chris@16: , Callable1 const &format Chris@16: , regex_constants::match_flag_type Chris@16: , mpl::size_t<1> Chris@16: ) const Chris@16: { Chris@16: #if BOOST_WORKAROUND(__GNUC__, == 4) && (__GNUC_MINOR__ == 0) Chris@16: return this->format2_(out, detail::as_callable(format)(*this)); Chris@16: #else Chris@16: return this->format2_(out, format(*this)); Chris@16: #endif Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: OutputIterator format_ Chris@16: ( Chris@16: OutputIterator out Chris@16: , Callable2 const &format Chris@16: , regex_constants::match_flag_type Chris@16: , mpl::size_t<2> Chris@16: ) const Chris@16: { Chris@16: #if BOOST_WORKAROUND(__GNUC__, == 4) && (__GNUC_MINOR__ == 0) Chris@16: return detail::as_callable(format)(*this, out); Chris@16: #else Chris@16: return format(*this, out); Chris@16: #endif Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: OutputIterator format_ Chris@16: ( Chris@16: OutputIterator out Chris@16: , Callable3 const &format Chris@16: , regex_constants::match_flag_type flags Chris@16: , mpl::size_t<3> Chris@16: ) const Chris@16: { Chris@16: #if BOOST_WORKAROUND(__GNUC__, == 4) && (__GNUC_MINOR__ == 0) Chris@16: return detail::as_callable(format)(*this, out, flags); Chris@16: #else Chris@16: return format(*this, out, flags); Chris@16: #endif Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: OutputIterator format_ Chris@16: ( Chris@16: OutputIterator out Chris@16: , Expr const &format Chris@16: , regex_constants::match_flag_type Chris@16: , mpl::size_t<4> Chris@16: ) const Chris@16: { Chris@16: // detail::ReplaceAlgo may be an incomplete type at this point, so Chris@16: // we can't construct it directly. Chris@16: typedef typename mpl::if_c::type ReplaceAlgo; Chris@16: return this->format2_(out, ReplaceAlgo()(format, 0, *this)); Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: OutputIterator format_ecma_262_(ForwardIterator cur, ForwardIterator end, OutputIterator out) const Chris@16: { Chris@16: while(cur != end) Chris@16: { Chris@16: switch(*cur) Chris@16: { Chris@16: case BOOST_XPR_CHAR_(char_type, '$'): Chris@16: out = this->format_backref_(++cur, end, out); Chris@16: break; Chris@16: Chris@16: default: Chris@16: *out++ = *cur++; Chris@16: break; Chris@16: } Chris@16: } Chris@16: Chris@16: return out; Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: OutputIterator format_sed_(ForwardIterator cur, ForwardIterator end, OutputIterator out) const Chris@16: { Chris@16: while(cur != end) Chris@16: { Chris@16: switch(*cur) Chris@16: { Chris@16: case BOOST_XPR_CHAR_(char_type, '&'): Chris@16: ++cur; Chris@16: out = std::copy(this->sub_matches_[ 0 ].first, this->sub_matches_[ 0 ].second, out); Chris@16: break; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, '\\'): Chris@16: out = this->format_escape_(++cur, end, out); Chris@16: break; Chris@16: Chris@16: default: Chris@16: *out++ = *cur++; Chris@16: break; Chris@16: } Chris@16: } Chris@16: Chris@16: return out; Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: OutputIterator format_perl_(ForwardIterator cur, ForwardIterator end, OutputIterator out) const Chris@16: { Chris@16: detail::case_converting_iterator iout(out, this->traits_.get()); Chris@16: Chris@16: while(cur != end) Chris@16: { Chris@16: switch(*cur) Chris@16: { Chris@16: case BOOST_XPR_CHAR_(char_type, '$'): Chris@16: iout = this->format_backref_(++cur, end, iout); Chris@16: break; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, '\\'): Chris@16: if(++cur != end && BOOST_XPR_CHAR_(char_type, 'g') == *cur) Chris@16: { Chris@16: iout = this->format_named_backref_(++cur, end, iout); Chris@16: } Chris@16: else Chris@16: { Chris@16: iout = this->format_escape_(cur, end, iout); Chris@16: } Chris@16: break; Chris@16: Chris@16: default: Chris@16: *iout++ = *cur++; Chris@16: break; Chris@16: } Chris@16: } Chris@16: Chris@16: return iout.base(); Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: OutputIterator format_all_(ForwardIterator cur, ForwardIterator end, OutputIterator out) const Chris@16: { Chris@16: detail::case_converting_iterator iout(out, this->traits_.get()); Chris@16: iout = this->format_all_impl_(cur, end, iout); Chris@16: BOOST_XPR_ENSURE_(cur == end Chris@16: , regex_constants::error_paren, "unbalanced parentheses in format string"); Chris@16: return iout.base(); Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: OutputIterator format_all_impl_(ForwardIterator &cur, ForwardIterator end, OutputIterator out, bool metacolon = false) const Chris@16: { Chris@16: int max = 0, sub = 0; Chris@16: detail::noop_output_iterator noop; Chris@16: Chris@16: while(cur != end) Chris@16: { Chris@16: switch(*cur) Chris@16: { Chris@16: case BOOST_XPR_CHAR_(char_type, '$'): Chris@16: out = this->format_backref_(++cur, end, out); Chris@16: break; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, '\\'): Chris@16: if(++cur != end && BOOST_XPR_CHAR_(char_type, 'g') == *cur) Chris@16: { Chris@16: out = this->format_named_backref_(++cur, end, out); Chris@16: } Chris@16: else Chris@16: { Chris@16: out = this->format_escape_(cur, end, out); Chris@16: } Chris@16: break; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, '('): Chris@16: out = this->format_all_impl_(++cur, end, out); Chris@16: BOOST_XPR_ENSURE_(BOOST_XPR_CHAR_(char_type, ')') == *(cur-1) Chris@16: , regex_constants::error_paren, "unbalanced parentheses in format string"); Chris@16: break; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, '?'): Chris@16: BOOST_XPR_ENSURE_(++cur != end Chris@16: , regex_constants::error_subreg, "malformed conditional in format string"); Chris@16: max = static_cast(this->size() - 1); Chris@16: sub = detail::toi(cur, end, *this->traits_, 10, max); Chris@16: BOOST_XPR_ENSURE_(0 != sub, regex_constants::error_subreg, "invalid back-reference"); Chris@16: if(this->sub_matches_[ sub ].matched) Chris@16: { Chris@16: out = this->format_all_impl_(cur, end, out, true); Chris@16: if(BOOST_XPR_CHAR_(char_type, ':') == *(cur-1)) Chris@16: this->format_all_impl_(cur, end, noop); Chris@16: } Chris@16: else Chris@16: { Chris@16: this->format_all_impl_(cur, end, noop, true); Chris@16: if(BOOST_XPR_CHAR_(char_type, ':') == *(cur-1)) Chris@16: out = this->format_all_impl_(cur, end, out); Chris@16: } Chris@16: return out; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, ':'): Chris@16: if(metacolon) Chris@16: { Chris@16: BOOST_FALLTHROUGH; Chris@16: case BOOST_XPR_CHAR_(char_type, ')'): Chris@16: ++cur; Chris@16: return out; Chris@16: } Chris@16: BOOST_FALLTHROUGH; Chris@16: Chris@16: default: Chris@16: *out++ = *cur++; Chris@16: break; Chris@16: } Chris@16: } Chris@16: Chris@16: return out; Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: OutputIterator format_backref_ Chris@16: ( Chris@16: ForwardIterator &cur Chris@16: , ForwardIterator end Chris@16: , OutputIterator out Chris@16: ) const Chris@16: { Chris@16: if(cur == end) Chris@16: { Chris@16: *out++ = BOOST_XPR_CHAR_(char_type, '$'); Chris@16: } Chris@16: else if(BOOST_XPR_CHAR_(char_type, '$') == *cur) Chris@16: { Chris@16: *out++ = *cur++; Chris@16: } Chris@16: else if(BOOST_XPR_CHAR_(char_type, '&') == *cur) // whole match Chris@16: { Chris@16: ++cur; Chris@16: out = std::copy(this->sub_matches_[ 0 ].first, this->sub_matches_[ 0 ].second, out); Chris@16: } Chris@16: else if(BOOST_XPR_CHAR_(char_type, '`') == *cur) // prefix Chris@16: { Chris@16: ++cur; Chris@16: out = std::copy(this->prefix().first, this->prefix().second, out); Chris@16: } Chris@16: else if(BOOST_XPR_CHAR_(char_type, '\'') == *cur) // suffix Chris@16: { Chris@16: ++cur; Chris@16: out = std::copy(this->suffix().first, this->suffix().second, out); Chris@16: } Chris@16: else if(-1 != this->traits_->value(*cur, 10)) // a sub-match Chris@16: { Chris@16: int max = static_cast(this->size() - 1); Chris@16: int sub = detail::toi(cur, end, *this->traits_, 10, max); Chris@16: BOOST_XPR_ENSURE_(0 != sub, regex_constants::error_subreg, "invalid back-reference"); Chris@16: if(this->sub_matches_[ sub ].matched) Chris@16: out = std::copy(this->sub_matches_[ sub ].first, this->sub_matches_[ sub ].second, out); Chris@16: } Chris@16: else Chris@16: { Chris@16: *out++ = BOOST_XPR_CHAR_(char_type, '$'); Chris@16: *out++ = *cur++; Chris@16: } Chris@16: Chris@16: return out; Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: OutputIterator format_escape_ Chris@16: ( Chris@16: ForwardIterator &cur Chris@16: , ForwardIterator end Chris@16: , OutputIterator out Chris@16: ) const Chris@16: { Chris@16: using namespace regex_constants; Chris@16: ForwardIterator tmp; Chris@16: // define an unsigned type the same size as char_type Chris@16: typedef typename boost::uint_t::least uchar_t; Chris@16: BOOST_MPL_ASSERT_RELATION(sizeof(uchar_t), ==, sizeof(char_type)); Chris@16: typedef numeric::conversion_traits converstion_traits; Chris@16: numeric::converter converter; Chris@16: Chris@16: if(cur == end) Chris@16: { Chris@16: *out++ = BOOST_XPR_CHAR_(char_type, '\\'); Chris@16: return out; Chris@16: } Chris@16: Chris@16: char_type ch = *cur++; Chris@16: switch(ch) Chris@16: { Chris@16: case BOOST_XPR_CHAR_(char_type, 'a'): Chris@16: *out++ = BOOST_XPR_CHAR_(char_type, '\a'); Chris@16: break; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, 'e'): Chris@16: *out++ = converter(27); Chris@16: break; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, 'f'): Chris@16: *out++ = BOOST_XPR_CHAR_(char_type, '\f'); Chris@16: break; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, 'n'): Chris@16: *out++ = BOOST_XPR_CHAR_(char_type, '\n'); Chris@16: break; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, 'r'): Chris@16: *out++ = BOOST_XPR_CHAR_(char_type, '\r'); Chris@16: break; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, 't'): Chris@16: *out++ = BOOST_XPR_CHAR_(char_type, '\t'); Chris@16: break; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, 'v'): Chris@16: *out++ = BOOST_XPR_CHAR_(char_type, '\v'); Chris@16: break; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, 'x'): Chris@16: BOOST_XPR_ENSURE_(cur != end, error_escape, "unexpected end of format found"); Chris@16: if(BOOST_XPR_CHAR_(char_type, '{') == *cur) Chris@16: { Chris@16: BOOST_XPR_ENSURE_(++cur != end, error_escape, "unexpected end of format found"); Chris@16: tmp = cur; Chris@16: *out++ = converter(detail::toi(cur, end, *this->traits_, 16, 0xffff)); Chris@16: BOOST_XPR_ENSURE_(4 == std::distance(tmp, cur) && cur != end && BOOST_XPR_CHAR_(char_type, '}') == *cur++ Chris@16: , error_escape, "invalid hex escape : must be \\x { HexDigit HexDigit HexDigit HexDigit }"); Chris@16: } Chris@16: else Chris@16: { Chris@16: tmp = cur; Chris@16: *out++ = converter(detail::toi(cur, end, *this->traits_, 16, 0xff)); Chris@16: BOOST_XPR_ENSURE_(2 == std::distance(tmp, cur), error_escape Chris@16: , "invalid hex escape : must be \\x HexDigit HexDigit"); Chris@16: } Chris@16: break; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, 'c'): Chris@16: BOOST_XPR_ENSURE_(cur != end, error_escape, "unexpected end of format found"); Chris@16: BOOST_XPR_ENSURE_ Chris@16: ( Chris@16: this->traits_->in_range(BOOST_XPR_CHAR_(char_type, 'a'), BOOST_XPR_CHAR_(char_type, 'z'), *cur) Chris@16: || this->traits_->in_range(BOOST_XPR_CHAR_(char_type, 'A'), BOOST_XPR_CHAR_(char_type, 'Z'), *cur) Chris@16: , error_escape Chris@16: , "invalid escape control letter; must be one of a-z or A-Z" Chris@16: ); Chris@16: // Convert to character according to ECMA-262, section 15.10.2.10: Chris@16: *out++ = converter(*cur % 32); Chris@16: ++cur; Chris@16: break; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, 'l'): Chris@16: if(!set_transform(out, detail::op_lower, detail::scope_next)) Chris@16: { Chris@16: *out++ = BOOST_XPR_CHAR_(char_type, 'l'); Chris@16: } Chris@16: break; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, 'L'): Chris@16: if(!set_transform(out, detail::op_lower, detail::scope_rest)) Chris@16: { Chris@16: *out++ = BOOST_XPR_CHAR_(char_type, 'L'); Chris@16: } Chris@16: break; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, 'u'): Chris@16: if(!set_transform(out, detail::op_upper, detail::scope_next)) Chris@16: { Chris@16: *out++ = BOOST_XPR_CHAR_(char_type, 'u'); Chris@16: } Chris@16: break; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, 'U'): Chris@16: if(!set_transform(out, detail::op_upper, detail::scope_rest)) Chris@16: { Chris@16: *out++ = BOOST_XPR_CHAR_(char_type, 'U'); Chris@16: } Chris@16: break; Chris@16: Chris@16: case BOOST_XPR_CHAR_(char_type, 'E'): Chris@16: if(!set_transform(out, detail::op_none, detail::scope_rest)) Chris@16: { Chris@16: *out++ = BOOST_XPR_CHAR_(char_type, 'E'); Chris@16: } Chris@16: break; Chris@16: Chris@16: default: Chris@16: // BUGBUG what about backreferences like \12 ? Chris@16: if(0 < this->traits_->value(ch, 10)) Chris@16: { Chris@16: int sub = this->traits_->value(ch, 10); Chris@16: if(this->sub_matches_[ sub ].matched) Chris@16: out = std::copy(this->sub_matches_[ sub ].first, this->sub_matches_[ sub ].second, out); Chris@16: } Chris@16: else Chris@16: { Chris@16: *out++ = ch; Chris@16: } Chris@16: break; Chris@16: } Chris@16: Chris@16: return out; Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: OutputIterator format_named_backref_ Chris@16: ( Chris@16: ForwardIterator &cur Chris@16: , ForwardIterator end Chris@16: , OutputIterator out Chris@16: ) const Chris@16: { Chris@16: using namespace regex_constants; Chris@16: BOOST_XPR_ENSURE_(cur != end && BOOST_XPR_CHAR_(char_type, '<') == *cur++ Chris@16: , error_badmark, "invalid named back-reference"); Chris@16: ForwardIterator begin = cur; Chris@16: for(; cur != end && BOOST_XPR_CHAR_(char_type, '>') != *cur; ++cur) Chris@16: {} Chris@16: BOOST_XPR_ENSURE_(cur != begin && cur != end && BOOST_XPR_CHAR_(char_type, '>') == *cur Chris@16: , error_badmark, "invalid named back-reference"); Chris@16: Chris@16: string_type name(begin, cur++); Chris@16: for(std::size_t i = 0; i < this->named_marks_.size(); ++i) Chris@16: { Chris@16: if(this->named_marks_[i].name_ == name) Chris@16: { Chris@16: std::size_t sub = this->named_marks_[i].mark_nbr_; Chris@16: return std::copy(this->sub_matches_[ sub ].first, this->sub_matches_[ sub ].second, out); Chris@16: } Chris@16: } Chris@16: Chris@16: BOOST_THROW_EXCEPTION(regex_error(error_badmark, "invalid named back-reference")); Chris@16: // Should never get here Chris@16: return out; Chris@16: } Chris@16: Chris@16: regex_id_type regex_id_; Chris@16: detail::sub_match_vector sub_matches_; Chris@16: boost::optional base_; Chris@16: boost::optional > prefix_; Chris@16: boost::optional > suffix_; Chris@16: nested_results_type nested_results_; Chris@16: intrusive_ptr extras_ptr_; Chris@16: intrusive_ptr const> traits_; Chris@16: detail::action_args_type args_; Chris@16: std::vector > named_marks_; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // regex_id_filter_predicate Chris@16: // Chris@16: template Chris@16: struct regex_id_filter_predicate Chris@16: : std::unary_function, bool> Chris@16: { Chris@16: regex_id_filter_predicate(regex_id_type regex_id) Chris@16: : regex_id_(regex_id) Chris@16: { Chris@16: } Chris@16: Chris@16: bool operator ()(match_results const &res) const Chris@16: { Chris@16: return this->regex_id_ == res.regex_id(); Chris@16: } Chris@16: Chris@16: private: Chris@16: Chris@16: regex_id_type regex_id_; Chris@16: }; Chris@16: Chris@16: }} // namespace boost::xpressive Chris@16: Chris@16: #ifdef BOOST_HAS_CONCEPTS Chris@16: // Better living through concepts. :-P Chris@16: namespace std Chris@16: { Chris@16: template Chris@16: concept_map OutputIterator< Chris@16: boost::xpressive::detail::case_converting_iterator Chris@16: , Char_ Chris@16: > Chris@16: {}; Chris@16: Chris@16: template Chris@16: concept_map OutputIterator< Chris@16: boost::xpressive::detail::noop_output_iterator Chris@16: , Char_ Chris@16: > Chris@16: {}; Chris@16: } Chris@16: #endif Chris@16: Chris@16: #endif