Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/boost/xpressive/match_results.hpp @ 29

Last change on this file since 29 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 17.4 KB
Line 
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 2004 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#ifndef BOOST_XPRESSIVE_MATCH_RESULTS_HPP_EAN_10_04_2005
12#define BOOST_XPRESSIVE_MATCH_RESULTS_HPP_EAN_10_04_2005
13
14// MS compatible compilers support #pragma once
15#if defined(_MSC_VER) && (_MSC_VER >= 1020)
16# pragma once
17#endif
18
19#include <iterator>
20#include <boost/assert.hpp>
21#include <boost/shared_ptr.hpp>
22#include <boost/iterator_adaptors.hpp>
23#if BOOST_ITERATOR_ADAPTORS_VERSION >= 0x0200
24# include <boost/iterator/filter_iterator.hpp>
25#endif
26#include <boost/xpressive/regex_constants.hpp>
27#include <boost/xpressive/detail/detail_fwd.hpp>
28#include <boost/xpressive/detail/core/sub_match_vector.hpp>
29#include <boost/xpressive/detail/utility/sequence_stack.hpp>
30#include <boost/xpressive/detail/core/results_cache.hpp>
31#include <boost/xpressive/detail/core/action_state.hpp>
32#include <boost/xpressive/detail/utility/literals.hpp>
33#include <boost/xpressive/detail/utility/algorithm.hpp>
34
35namespace boost { namespace xpressive { namespace detail
36{
37
38///////////////////////////////////////////////////////////////////////////////
39// results_extras
40//
41template<typename BidiIter>
42struct results_extras
43{
44    sequence_stack<sub_match_impl<BidiIter> > sub_match_stack_;
45    results_cache<BidiIter> results_cache_;
46};
47
48///////////////////////////////////////////////////////////////////////////////
49// results_traits
50//
51template<typename Char>
52struct results_traits
53{
54    static int value(Char ch, int radix = 10)
55    {
56        BOOST_ASSERT(10 == radix);
57        if(ch >= BOOST_XPR_CHAR_(Char, '0') && ch <= BOOST_XPR_CHAR_(Char, '9'))
58        {
59            return ch - BOOST_XPR_CHAR_(Char, '0');
60        }
61        return -1;
62    }
63};
64
65} // namespace detail
66
67///////////////////////////////////////////////////////////////////////////////
68// match_results
69/// \brief Class template match_results\<\> holds the results of a regex_match() or a
70/// regex_search() as a collection of sub_match objects.
71///
72/// Class template match_results\<\> denotes a collection of sequences representing the result of
73/// a regular expression match. Storage for the collection is allocated and freed as necessary by
74/// the member functions of class match_results\<\>.
75///
76/// The class template match_results\<\> conforms to the requirements of a Sequence, as specified
77/// in (lib.sequence.reqmts), except that only operations defined for const-qualified Sequences are
78/// supported.
79template<typename BidiIter>
80struct match_results
81{
82private:
83    struct dummy { int i_; };
84    typedef int dummy::*bool_type;
85
86public:
87    typedef typename iterator_value<BidiIter>::type char_type;
88    typedef std::basic_string<char_type> string_type;
89    typedef std::size_t size_type;
90    typedef sub_match<BidiIter> value_type;
91    typedef typename iterator_difference<BidiIter>::type difference_type;
92    typedef value_type const &reference;
93    typedef value_type const &const_reference;
94
95    typedef typename detail::sub_match_vector<BidiIter>::iterator iterator;
96    typedef typename detail::sub_match_vector<BidiIter>::const_iterator const_iterator;
97    typedef typename detail::nested_results<BidiIter> nested_results_type;
98
99    /// \post regex_id() == 0
100    /// \post size()     == 0
101    /// \post empty()    == true
102    match_results()
103      : regex_id_(0)
104      , sub_matches_()
105      , base_()
106      , prefix_()
107      , suffix_()
108      , nested_results_()
109      , action_state_()
110      , extras_ptr_()
111    {
112    }
113
114    /// \param that The match_results object to copy
115    /// \post regex_id()  == that.regex_id().
116    /// \post size()      == that.size().
117    /// \post empty()     == that.empty().
118    /// \post str(n)      == that.str(n) for all positive integers n \< that.size().
119    /// \post prefix()    == that.prefix().
120    /// \post suffix()    == that.suffix().
121    /// \post (*this)[n]  == that[n] for all positive integers n \< that.size().
122    /// \post length(n)   == that.length(n) for all positive integers n \< that.size().
123    /// \post position(n) == that.position(n) for all positive integers n \< that.size().
124    match_results(match_results<BidiIter> const &that)
125      : regex_id_(that.regex_id_)
126      , sub_matches_()
127      , base_()
128      , prefix_()
129      , suffix_()
130      , nested_results_()
131      , action_state_(that.action_state_)
132      , extras_ptr_()
133    {
134        if(that)
135        {
136            extras_type &extras = this->get_extras_();
137            std::size_t size = that.sub_matches_.size();
138            detail::sub_match_impl<BidiIter> *sub_matches = extras.sub_match_stack_.push_sequence(size);
139            detail::core_access<BidiIter>::init_sub_match_vector(this->sub_matches_, sub_matches, size, that.sub_matches_);
140
141            // BUGBUG this doesn't share the extras::sequence_stack
142            this->nested_results_ = that.nested_results_;
143            this->prefix_ = that.prefix_;
144            this->suffix_ = that.suffix_;
145            this->base_ = that.base_;
146        }
147    }
148
149    ~match_results()
150    {
151    }
152
153    /// \param that The match_results object to copy.
154    /// \post regex_id()  == that.regex_id().
155    /// \post size()      == that.size().
156    /// \post empty()     == that.empty().
157    /// \post str(n)      == that.str(n) for all positive integers n \< that.size().
158    /// \post prefix()    == that.prefix().
159    /// \post suffix()    == that.suffix().
160    /// \post (*this)[n]  == that[n] for all positive integers n \< that.size().
161    /// \post length(n)   == that.length(n) for all positive integers n \< that.size().
162    /// \post position(n) == that.position(n) for all positive integers n \< that.size().
163    match_results<BidiIter> &operator =(match_results<BidiIter> const &that)
164    {
165        match_results<BidiIter>(that).swap(*this);
166        return *this;
167    }
168
169    /// Returns the number of sub_match elements stored in *this.
170    ///
171    size_type size() const
172    {
173        return this->sub_matches_.size();
174    }
175
176    /// Returns size() == 0.
177    ///
178    bool empty() const
179    {
180        return 0 == this->size();
181    }
182
183    /// Returns (*this)[sub].length().
184    ///
185    difference_type length(size_type sub = 0) const
186    {
187        return (*this)[ sub ].length();
188    }
189
190    /// If !(*this)[sub].matched then returns -1. Otherwise returns std::distance(base, (*this)[sub].first),
191    /// where base is the start iterator of the sequence that was searched. [Note – unless this is part
192    /// of a repeated search with a regex_iterator then base is the same as prefix().first – end note]
193    difference_type position(size_type sub = 0) const
194    {
195        return (*this)[ sub ].matched ? std::distance(this->base_, (*this)[ sub ].first) : -1;
196    }
197
198    /// Returns string_type((*this)[sub]).
199    ///
200    string_type str(size_type sub = 0) const
201    {
202        return (*this)[ sub ].str();
203    }
204
205    /// Returns a reference to the sub_match object representing the sequence that
206    /// matched marked sub-expression sub. If sub == 0 then returns a reference to a sub_match object
207    /// representing the sequence that matched the whole regular expression.
208    /// \pre sub \< (*this).size().
209    const_reference operator [](size_type sub) const
210    {
211        return this->sub_matches_[ sub ];
212    }
213
214    /// \overload
215    ///
216    const_reference operator [](detail::mark_tag const &mark) const
217    {
218        return this->sub_matches_[ detail::get_mark_number(mark) ];
219    }
220
221    /// Returns a reference to the sub_match object representing the character sequence from
222    /// the start of the string being matched/searched, to the start of the match found.
223    ///
224    const_reference prefix() const
225    {
226        return this->prefix_;
227    }
228
229    /// Returns a reference to the sub_match object representing the character sequence from
230    /// the end of the match found to the end of the string being matched/searched.
231    ///
232    const_reference suffix() const
233    {
234        return this->suffix_;
235    }
236
237    /// Returns a starting iterator that enumerates over all the marked sub-expression matches
238    /// stored in *this.
239    ///
240    const_iterator begin() const
241    {
242        return this->sub_matches_.begin();
243    }
244
245    /// Returns a terminating iterator that enumerates over all the marked sub-expression
246    /// matches stored in *this.
247    ///
248    const_iterator end() const
249    {
250        return this->sub_matches_.end();
251    }
252
253    /// Returns a true value if(*this)[0].matched, else returns a false value.
254    ///
255    operator bool_type() const
256    {
257        return (*this)[ 0 ].matched ? &dummy::i_ : 0;
258    }
259
260    /// Returns true if empty() || !(*this)[0].matched, else returns false.
261    ///
262    bool operator !() const
263    {
264        return this->empty() || !(*this)[ 0 ].matched;
265    }
266
267    /// Returns the id of the basic_regex object most recently used with this match_results object.
268    ///
269    regex_id_type regex_id() const
270    {
271        return this->regex_id_;
272    }
273
274    /// Returns a Sequence of nested match_results elements.
275    ///
276    nested_results_type const &nested_results() const
277    {
278        return this->nested_results_;
279    }
280
281    /// Copies the character sequence [fmt.begin(), fmt.end()) to OutputIterator out. For each format
282    /// specifier or escape sequence in fmt, replace that sequence with either the character(s) it
283    /// represents, or the sequence within *this to which it refers. The bitmasks specified in flags
284    /// determines what format specifiers or escape sequences are recognized, by default this is the
285    /// format used by ECMA-262, ECMAScript Language Specification, Chapter 15 part 5.4.11 String.prototype.replace.
286    template<typename OutputIterator>
287    OutputIterator format
288    (
289        OutputIterator out
290      , const string_type &fmt
291      , regex_constants::match_flag_type flags = regex_constants::format_default
292    ) const
293    {
294        detail::results_traits<char_type> traits;
295        typename string_type::const_iterator cur = fmt.begin(), end = fmt.end();
296
297        if(0 != (regex_constants::format_literal & flags))
298        {
299            out = std::copy(cur, end, out);
300        }
301        else while(cur != end)
302        {
303            if(BOOST_XPR_CHAR_(char_type, '$') != *cur)
304            {
305                *out++ = *cur++;
306            }
307            else if(++cur == end)
308            {
309                *out++ = BOOST_XPR_CHAR_(char_type, '$');
310            }
311            else if(BOOST_XPR_CHAR_(char_type, '$') == *cur)
312            {
313                *out++ = *cur++;
314            }
315            else if(BOOST_XPR_CHAR_(char_type, '&') == *cur) // whole match
316            {
317                ++cur;
318                out = std::copy((*this)[ 0 ].first, (*this)[ 0 ].second, out);
319            }
320            else if(BOOST_XPR_CHAR_(char_type, '`') == *cur) // prefix
321            {
322                ++cur;
323                out = std::copy(this->prefix().first, this->prefix().second, out);
324            }
325            else if(BOOST_XPR_CHAR_(char_type, '\'') == *cur) // suffix
326            {
327                ++cur;
328                out = std::copy(this->suffix().first, this->suffix().second, out);
329            }
330            else if(-1 != traits.value(*cur, 10)) // a sub-match
331            {
332                int max = static_cast<int>(this->size() - 1);
333                int br_nbr = detail::toi(cur, end, traits, 10, max);
334                detail::ensure(0 != br_nbr, regex_constants::error_subreg, "invalid back-reference");
335                out = std::copy((*this)[ br_nbr ].first, (*this)[ br_nbr ].second, out);
336            }
337            else
338            {
339                *out++ = BOOST_XPR_CHAR_(char_type, '$');
340                *out++ = *cur++;
341            }
342        }
343
344        return out;
345    }
346
347    /// Returns a copy of the string fmt. For each format specifier or escape sequence in fmt,
348    /// replace that sequence with either the character(s) it represents, or the sequence within
349    /// *this to which it refers. The bitmasks specified in flags determines what format specifiers
350    /// or escape sequences are recognized, by default this is the format used by ECMA-262,
351    /// ECMAScript Language Specification, Chapter 15 part 5.4.11 String.prototype.replace.
352    string_type format(const string_type &fmt, regex_constants::match_flag_type flags = regex_constants::format_default) const
353    {
354        string_type result;
355        result.reserve(fmt.length() * 2);
356        this->format(std::back_inserter(result), fmt, flags);
357        return result;
358    }
359
360    /// Swaps the contents of two match_results objects. Guaranteed not to throw.
361    /// \param that The match_results object to swap with.
362    /// \post *this contains the sequence of matched sub-expressions that were in that,
363    /// that contains the sequence of matched sub-expressions that were in *this.
364    /// \throw nothrow
365    void swap(match_results<BidiIter> &that) // throw()
366    {
367        std::swap(this->regex_id_, that.regex_id_);
368        this->sub_matches_.swap(that.sub_matches_);
369        std::swap(this->base_, that.base_);
370        std::swap(this->prefix_, that.prefix_);
371        std::swap(this->suffix_, that.suffix_);
372        this->nested_results_.swap(that.nested_results_);
373        std::swap(this->action_state_, that.action_state_);
374        this->extras_ptr_.swap(that.extras_ptr_);
375    }
376
377    /// INTERNAL ONLY
378    match_results<BidiIter> const &operator ()(regex_id_type regex_id, size_type index = 0) const
379    {
380        // BUGBUG this is linear, make it O(1)
381        static match_results<BidiIter> const s_null;
382
383        regex_id_filter_predicate<BidiIter> pred(regex_id);
384        typename nested_results_type::const_iterator
385            begin = this->nested_results_.begin()
386          , end = this->nested_results_.end()
387          , cur = detail::find_nth_if(begin, end, index, pred);
388
389        return (cur == end) ? s_null : *cur;
390    }
391
392    /// INTERNAL ONLY
393    match_results<BidiIter> const &operator ()(basic_regex<BidiIter> const &rex, std::size_t index = 0) const
394    {
395        return (*this)(rex.regex_id(), index);
396    }
397
398    // state:
399    /// INTERNAL ONLY
400    template<typename State>
401    void set_action_state(State &state)
402    {
403        this->action_state_.set(state);
404    }
405
406    /// INTERNAL ONLY
407    template<typename State>
408    State &get_action_state() const
409    {
410        return this->action_state_.BOOST_NESTED_TEMPLATE get<State>();
411    }
412
413private:
414
415    friend struct detail::core_access<BidiIter>;
416    typedef detail::results_extras<BidiIter> extras_type;
417
418    /// INTERNAL ONLY
419    void init_
420    (
421        regex_id_type regex_id
422      , detail::sub_match_impl<BidiIter> *sub_matches
423      , size_type size
424    )
425    {
426        this->regex_id_ = regex_id;
427        detail::core_access<BidiIter>::init_sub_match_vector(this->sub_matches_, sub_matches, size);
428    }
429
430    /// INTERNAL ONLY
431    extras_type &get_extras_()
432    {
433        if(!this->extras_ptr_)
434        {
435            this->extras_ptr_.reset(new extras_type);
436        }
437
438        return *this->extras_ptr_;
439    }
440
441    /// INTERNAL ONLY
442    void set_prefix_suffix_(BidiIter begin, BidiIter end)
443    {
444        this->base_ = begin;
445
446        this->prefix_.first = begin;
447        this->prefix_.second = (*this)[ 0 ].first;
448        this->prefix_.matched = this->prefix_.first != this->prefix_.second;
449
450        this->suffix_.first = (*this)[ 0 ].second;
451        this->suffix_.second = end;
452        this->suffix_.matched = this->suffix_.first != this->suffix_.second;
453
454        typename nested_results_type::iterator ibegin = this->nested_results_.begin();
455        typename nested_results_type::iterator iend = this->nested_results_.end();
456        for( ; ibegin != iend; ++ibegin )
457        {
458            ibegin->set_prefix_suffix_(begin, end);
459        }
460    }
461
462    /// INTERNAL ONLY
463    void reset_()
464    {
465        detail::core_access<BidiIter>::init_sub_match_vector(this->sub_matches_, 0, 0);
466    }
467
468    /// INTERNAL ONLY
469    void set_base_(BidiIter base)
470    {
471        this->base_ = base;
472
473        typename nested_results_type::iterator ibegin = this->nested_results_.begin();
474        typename nested_results_type::iterator iend = this->nested_results_.end();
475        for( ; ibegin != iend; ++ibegin )
476        {
477            ibegin->set_base_(base);
478        }
479    }
480
481    regex_id_type regex_id_;
482    detail::sub_match_vector<BidiIter> sub_matches_;
483    BidiIter base_;
484    sub_match<BidiIter> prefix_;
485    sub_match<BidiIter> suffix_;
486    nested_results_type nested_results_;
487    detail::action_state action_state_;
488    shared_ptr<extras_type> extras_ptr_;
489};
490
491///////////////////////////////////////////////////////////////////////////////
492// action_state_cast
493/// INTERNAL ONLY
494template<typename State, typename BidiIter>
495inline State &action_state_cast(match_results<BidiIter> const &what)
496{
497    return what.BOOST_NESTED_TEMPLATE get_action_state<State>();
498}
499
500///////////////////////////////////////////////////////////////////////////////
501// regex_id_filter_predicate
502//
503template<typename BidiIter>
504struct regex_id_filter_predicate
505  : std::unary_function<match_results<BidiIter>, bool>
506{
507    regex_id_filter_predicate(regex_id_type regex_id)
508      : regex_id_(regex_id)
509    {
510    }
511
512    bool operator ()(match_results<BidiIter> const &res) const
513    {
514        return this->regex_id_ == res.regex_id();
515    }
516
517private:
518
519    regex_id_type regex_id_;
520};
521
522}} // namespace boost::xpressive
523
524#endif
Note: See TracBrowser for help on using the repository browser.