1 ///////////////////////////////////////////////////////////////////////////////
2 // sequence.hpp
3 //
4 //  Copyright 2008 Eric Niebler. Distributed under the Boost
5 //  Software License, Version 1.0. (See accompanying file
6 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 
8 #ifndef BOOST_XPRESSIVE_DETAIL_DYNAMIC_SEQUENCE_HPP_EAN_04_10_2006
9 #define BOOST_XPRESSIVE_DETAIL_DYNAMIC_SEQUENCE_HPP_EAN_04_10_2006
10 
11 // MS compatible compilers support #pragma once
12 #if defined(_MSC_VER)
13 # pragma once
14 #endif
15 
16 #include <boost/assert.hpp>
17 #include <boost/intrusive_ptr.hpp>
18 #include <boost/xpressive/detail/utility/width.hpp>
19 #include <boost/xpressive/detail/detail_fwd.hpp>
20 
21 namespace boost { namespace xpressive { namespace detail
22 {
23 
24 ///////////////////////////////////////////////////////////////////////////////
25 // sequence
26 template<typename BidiIter>
27 struct sequence
28 {
sequenceboost::xpressive::detail::sequence29     sequence()
30       : pure_(true)
31       , width_(0)
32       , quant_(quant_none)
33       , head_()
34       , tail_(0)
35       , alt_end_xpr_()
36       , alternates_(0)
37     {
38     }
39 
40     template<typename Matcher>
sequenceboost::xpressive::detail::sequence41     sequence(intrusive_ptr<dynamic_xpression<Matcher, BidiIter> > const &xpr)
42       : pure_(Matcher::pure)
43       , width_(xpr->Matcher::get_width())
44       , quant_(static_cast<quant_enum>(Matcher::quant))
45       , head_(xpr)
46       , tail_(&xpr->next_)
47       , alt_end_xpr_()
48       , alternates_(0)
49     {
50     }
51 
52     template<typename Traits>
sequenceboost::xpressive::detail::sequence53     sequence(intrusive_ptr<dynamic_xpression<alternate_matcher<alternates_vector<BidiIter>, Traits>, BidiIter> > const &xpr)
54       : pure_(true)
55       , width_(0)
56       , quant_(quant_none)
57       , head_(xpr)
58       , tail_(&xpr->next_)
59       , alt_end_xpr_()
60       , alternates_(&xpr->alternates_)
61     {
62     }
63 
emptyboost::xpressive::detail::sequence64     bool empty() const
65     {
66         return !this->head_;
67     }
68 
operator +=boost::xpressive::detail::sequence69     sequence<BidiIter> &operator +=(sequence<BidiIter> const &that)
70     {
71         if(this->empty())
72         {
73             *this = that;
74         }
75         else if(!that.empty())
76         {
77             *this->tail_ = that.head_;
78             this->tail_ = that.tail_;
79             // keep track of sequence width and purity
80             this->width_ += that.width_;
81             this->pure_ = this->pure_ && that.pure_;
82             this->set_quant_();
83         }
84         return *this;
85     }
86 
operator |=boost::xpressive::detail::sequence87     sequence<BidiIter> &operator |=(sequence<BidiIter> that)
88     {
89         BOOST_ASSERT(!this->empty());
90         BOOST_ASSERT(0 != this->alternates_);
91 
92         // Keep track of width and purity
93         if(this->alternates_->empty())
94         {
95             this->width_ = that.width_;
96             this->pure_ = that.pure_;
97         }
98         else
99         {
100             this->width_ |= that.width_;
101             this->pure_ = this->pure_ && that.pure_;
102         }
103 
104         // through the wonders of reference counting, all alternates_ can share an end_alternate
105         if(!this->alt_end_xpr_)
106         {
107             this->alt_end_xpr_ = new alt_end_xpr_type;
108         }
109 
110         // terminate each alternate with an alternate_end_matcher
111         that += sequence(this->alt_end_xpr_);
112         this->alternates_->push_back(that.head_);
113         this->set_quant_();
114         return *this;
115     }
116 
repeatboost::xpressive::detail::sequence117     void repeat(quant_spec const &spec)
118     {
119         this->xpr().matchable()->repeat(spec, *this);
120     }
121 
xprboost::xpressive::detail::sequence122     shared_matchable<BidiIter> const &xpr() const
123     {
124         return this->head_;
125     }
126 
widthboost::xpressive::detail::sequence127     detail::width width() const
128     {
129         return this->width_;
130     }
131 
pureboost::xpressive::detail::sequence132     bool pure() const
133     {
134         return this->pure_;
135     }
136 
quantboost::xpressive::detail::sequence137     quant_enum quant() const
138     {
139         return this->quant_;
140     }
141 
142 private:
143     typedef dynamic_xpression<alternate_end_matcher, BidiIter> alt_end_xpr_type;
144 
set_quant_boost::xpressive::detail::sequence145     void set_quant_()
146     {
147         this->quant_ = (!is_unknown(this->width_) && this->pure_)
148           ? (!this->width_ ? quant_none : quant_fixed_width)
149           : quant_variable_width;
150     }
151 
152     bool pure_;
153     detail::width width_;
154     quant_enum quant_;
155     shared_matchable<BidiIter> head_;
156     shared_matchable<BidiIter> *tail_;
157     intrusive_ptr<alt_end_xpr_type> alt_end_xpr_;
158     alternates_vector<BidiIter> *alternates_;
159 };
160 
161 template<typename BidiIter>
operator +(sequence<BidiIter> left,sequence<BidiIter> const & right)162 inline sequence<BidiIter> operator +(sequence<BidiIter> left, sequence<BidiIter> const &right)
163 {
164     return left += right;
165 }
166 
167 template<typename BidiIter>
operator |(sequence<BidiIter> left,sequence<BidiIter> const & right)168 inline sequence<BidiIter> operator |(sequence<BidiIter> left, sequence<BidiIter> const &right)
169 {
170     return left |= right;
171 }
172 
173 }}} // namespace boost::xpressive::detail
174 
175 #endif
176