boost/xpressive/detail/dynamic/dynamic.hpp
/////////////////////////////////////////////////////////////////////////////// // dynamic.hpp // // Copyright 2004 Eric Niebler. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_XPRESSIVE_DETAIL_DYNAMIC_DYNAMIC_HPP_EAN_10_04_2005 #define BOOST_XPRESSIVE_DETAIL_DYNAMIC_DYNAMIC_HPP_EAN_10_04_2005 // MS compatible compilers support #pragma once #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #include <list> #include <utility> #include <algorithm> #include <boost/assert.hpp> #include <boost/mpl/int.hpp> #include <boost/mpl/assert.hpp> #include <boost/xpressive/detail/detail_fwd.hpp> #include <boost/xpressive/detail/core/quant_style.hpp> #include <boost/xpressive/detail/dynamic/matchable.hpp> #include <boost/xpressive/detail/core/icase.hpp> namespace boost { namespace xpressive { namespace detail { /////////////////////////////////////////////////////////////////////////////// // invalid_xpression // template<typename BidiIter> struct invalid_xpression : matchable<BidiIter> { invalid_xpression() : matchable<BidiIter>() { } bool match(state_type<BidiIter> &) const { BOOST_ASSERT(false); return false; } std::size_t get_width(state_type<BidiIter> *) const { return 0; } static void noop(matchable<BidiIter> const *) { } }; /////////////////////////////////////////////////////////////////////////////// // get_invalid_xpression // template<typename BidiIter> inline shared_ptr<matchable<BidiIter> const> const &get_invalid_xpression() { static invalid_xpression<BidiIter> const invalid_xpr; static shared_ptr<matchable<BidiIter> const> const invalid_ptr ( static_cast<matchable<BidiIter> const *>(&invalid_xpr) , &invalid_xpression<BidiIter>::noop ); return invalid_ptr; } /////////////////////////////////////////////////////////////////////////////// // dynamic_xpression // template<typename Matcher, typename BidiIter> struct dynamic_xpression : Matcher , matchable<BidiIter> { typedef typename iterator_value<BidiIter>::type char_type; shared_ptr<matchable<BidiIter> const> next_; dynamic_xpression(Matcher const &matcher = Matcher()) : Matcher(matcher) , next_(get_invalid_xpression<BidiIter>()) { } bool match(state_type<BidiIter> &state) const { return this->Matcher::match(state, *this->next_); } std::size_t get_width(state_type<BidiIter> *state) const { std::size_t this_width = this->Matcher::get_width(state); if(this_width == unknown_width()) return unknown_width(); std::size_t that_width = this->next_->get_width(state); if(that_width == unknown_width()) return unknown_width(); return this_width + that_width; } void link(xpression_linker<char_type> &linker) const { linker.link(*static_cast<Matcher const *>(this), this->next_.get()); this->next_->link(linker); } void peek(xpression_peeker<char_type> &peeker) const { this->peek_next_(peeker.peek(*static_cast<Matcher const *>(this)), peeker); } sequence<BidiIter> quantify ( quant_spec const &spec , std::size_t &hidden_mark_count , sequence<BidiIter> seq , alternates_factory<BidiIter> const &factory ) const { return this->quantify_(spec, hidden_mark_count, seq, quant_type<Matcher>(), factory, this); } bool is_quantifiable() const { return quant_type<Matcher>::value != (int)quant_none; } private: void peek_next_(mpl::true_, xpression_peeker<char_type> &peeker) const { this->next_->peek(peeker); } void peek_next_(mpl::false_, xpression_peeker<char_type> &) const { // no-op } sequence<BidiIter> quantify_ ( quant_spec const & , std::size_t & , sequence<BidiIter> , mpl::int_<quant_none> , alternates_factory<BidiIter> const & , void const * ) const; sequence<BidiIter> quantify_ ( quant_spec const & , std::size_t & , sequence<BidiIter> , mpl::int_<quant_fixed_width> , alternates_factory<BidiIter> const & , void const * ) const; sequence<BidiIter> quantify_ ( quant_spec const & , std::size_t & , sequence<BidiIter> , mpl::int_<quant_variable_width> , alternates_factory<BidiIter> const & , void const * ) const; sequence<BidiIter> quantify_ ( quant_spec const & , std::size_t & , sequence<BidiIter> , mpl::int_<quant_fixed_width> , alternates_factory<BidiIter> const & , mark_begin_matcher const * ) const; }; /////////////////////////////////////////////////////////////////////////////// // make_dynamic_xpression // template<typename BidiIter, typename Matcher> inline sequence<BidiIter> make_dynamic_xpression(Matcher const &matcher) { typedef dynamic_xpression<Matcher, BidiIter> xpression_type; std::auto_ptr<xpression_type> xpr(new xpression_type(matcher)); sequence<BidiIter> seq; seq.second = &xpr->next_; seq.first = xpr; return seq; } /////////////////////////////////////////////////////////////////////////////// // alternates_factory // template<typename BidiIter> struct alternates_factory { typedef std::vector<shared_ptr<matchable<BidiIter> const> > alternates_vector; virtual ~alternates_factory() {} virtual std::pair<sequence<BidiIter>, alternates_vector *> operator ()() const = 0; }; template<typename BidiIter, typename Traits> struct alternates_factory_impl : alternates_factory<BidiIter> { typedef typename alternates_factory<BidiIter>::alternates_vector alternates_vector; std::pair<sequence<BidiIter>, alternates_vector *> operator ()() const { typedef alternate_matcher<alternates_vector, Traits> alternate_matcher; typedef dynamic_xpression<alternate_matcher, BidiIter> alternate_xpression; shared_ptr<alternate_xpression> alt_xpr(new alternate_xpression); sequence<BidiIter> seq(alt_xpr, &alt_xpr->next_); return std::make_pair(seq, &alt_xpr->alternates_); } }; /////////////////////////////////////////////////////////////////////////////// // alternates_to_matchable // template<typename BidiIter> inline sequence<BidiIter> alternates_to_matchable ( std::list<sequence<BidiIter> > const &alternates , alternates_factory<BidiIter> const &factory ) { BOOST_ASSERT(0 != alternates.size()); // If there is only 1 alternate, just return it. if(1 == alternates.size()) { return alternates.front(); } typedef std::vector<shared_ptr<matchable<BidiIter> const> > alternates_vector; std::pair<sequence<BidiIter>, alternates_vector *> result = factory(); // through the wonders of reference counting, all alternates can share an end_alternate typedef dynamic_xpression<alternate_end_matcher, BidiIter> alternate_end_xpression; shared_ptr<alternate_end_xpression> end_alt_xpr(new alternate_end_xpression); // terminate each alternate with an alternate_end_matcher result.second->reserve(alternates.size()); typedef std::list<sequence<BidiIter> > alternates_list; typename alternates_list::const_iterator begin = alternates.begin(), end = alternates.end(); for(; begin != end; ++begin) { if(!begin->is_empty()) { result.second->push_back(begin->first); *begin->second = end_alt_xpr; } else { result.second->push_back(end_alt_xpr); } } return result.first; } /////////////////////////////////////////////////////////////////////////////// // matcher_wrapper // template<typename Matcher> struct matcher_wrapper : Matcher { matcher_wrapper(Matcher const &matcher = Matcher()) : Matcher(matcher) { } template<typename BidiIter> bool match(state_type<BidiIter> &state) const { return this->Matcher::match(state, matcher_wrapper<true_matcher>()); } template<typename Char> void link(xpression_linker<Char> &linker) const { linker.link(*static_cast<Matcher const *>(this), 0); } template<typename Char> void peek(xpression_peeker<Char> &peeker) const { peeker.peek(*static_cast<Matcher const *>(this)); } }; ////////////////////////////////////////////////////////////////////////// // dynamic_xpression::quantify_ // // unquantifiable template<typename Matcher, typename BidiIter> inline sequence<BidiIter> dynamic_xpression<Matcher, BidiIter>::quantify_ ( quant_spec const & , std::size_t & , sequence<BidiIter> , mpl::int_<quant_none> , alternates_factory<BidiIter> const & , void const * ) const { BOOST_ASSERT(false); // should never get here throw regex_error(regex_constants::error_badrepeat, "expression cannot be quantified"); } // fixed-width matchers template<typename Matcher, typename BidiIter> inline sequence<BidiIter> dynamic_xpression<Matcher, BidiIter>::quantify_ ( quant_spec const &spec , std::size_t &hidden_mark_count , sequence<BidiIter> seq , mpl::int_<quant_fixed_width> , alternates_factory<BidiIter> const &factory , void const * ) const { if(this->next_ != get_invalid_xpression<BidiIter>()) { return this->quantify_(spec, hidden_mark_count, seq, mpl::int_<quant_variable_width>(), factory, this); } typedef matcher_wrapper<Matcher> xpr_type; if(spec.greedy_) { simple_repeat_matcher<xpr_type, true> quant(*this, spec.min_, spec.max_); return make_dynamic_xpression<BidiIter>(quant); } else { simple_repeat_matcher<xpr_type, false> quant(*this, spec.min_, spec.max_); return make_dynamic_xpression<BidiIter>(quant); } } // variable-width, no mark template<typename Matcher, typename BidiIter> inline sequence<BidiIter> dynamic_xpression<Matcher, BidiIter>::quantify_ ( quant_spec const &spec , std::size_t &hidden_mark_count , sequence<BidiIter> seq , mpl::int_<quant_variable_width> , alternates_factory<BidiIter> const &factory , void const * ) const { // create a hidden mark so this expression can be quantified int mark_nbr = -static_cast<int>(++hidden_mark_count); mark_begin_matcher mark_begin(mark_nbr); mark_end_matcher mark_end(mark_nbr); sequence<BidiIter> new_seq = make_dynamic_xpression<BidiIter>(mark_begin); new_seq += seq; new_seq += make_dynamic_xpression<BidiIter>(mark_end); return new_seq.first->quantify(spec, hidden_mark_count, new_seq, factory); } // variable-width with mark template<typename Matcher, typename BidiIter> inline sequence<BidiIter> dynamic_xpression<Matcher, BidiIter>::quantify_ ( quant_spec const &spec , std::size_t & , sequence<BidiIter> seq , mpl::int_<quant_fixed_width> , alternates_factory<BidiIter> const &factory , mark_begin_matcher const * ) const { BOOST_ASSERT(spec.max_); // we should never get here if max is 0 int mark_number = this->mark_number_; // only bother creating a quantifier if max is greater than one if(1 < spec.max_) { unsigned int min = spec.min_ ? spec.min_ : 1U; detail::sequence<BidiIter> seq_quant; // TODO: statically bind the repeat_begin_matcher to the mark_begin for better perf seq_quant += make_dynamic_xpression<BidiIter>(repeat_begin_matcher(mark_number)); // TODO: statically bind the mark_end to the quantifier_end for better perf if(spec.greedy_) { repeat_end_matcher<true> end_quant(mark_number, min, spec.max_); seq += make_dynamic_xpression<BidiIter>(end_quant); } else { repeat_end_matcher<false> end_quant(mark_number, min, spec.max_); seq += make_dynamic_xpression<BidiIter>(end_quant); } seq_quant += seq; seq = seq_quant; } // if min is 0, the quant must be made alternate with an empty matcher. if(0 == spec.min_) { epsilon_mark_matcher mark(mark_number); std::list<sequence<BidiIter> > alts; alts.push_back(make_dynamic_xpression<BidiIter>(mark)); alts.push_back(seq); if(spec.greedy_) alts.reverse(); seq = alternates_to_matchable(alts, factory); } return seq; } }}} // namespace boost::xpressive::detail #endif