///////////////////////////////////////////////////////////////////////////////

// state.hpp

//

//  Copyright 2007 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_CORE_STATE_HPP_EAN_10_04_2005

#define BOOST_XPRESSIVE_DETAIL_CORE_STATE_HPP_EAN_10_04_2005



// MS compatible compilers support #pragma once

#if defined(_MSC_VER) && (_MSC_VER >= 1020)

# pragma once

#endif



#include <boost/noncopyable.hpp>

#include <boost/xpressive/detail/detail_fwd.hpp>

#include <boost/xpressive/detail/core/access.hpp>

#include <boost/xpressive/detail/core/action.hpp>

#include <boost/xpressive/detail/core/sub_match_vector.hpp>

#include <boost/xpressive/detail/utility/sequence_stack.hpp>

#include <boost/xpressive/detail/core/regex_impl.hpp>

#include <boost/xpressive/regex_constants.hpp>



namespace boost { namespace xpressive { namespace detail

{



///////////////////////////////////////////////////////////////////////////////

// match_context

//

template<typename BidiIter>

struct match_context

{

    typedef typename iterator_value<BidiIter>::type char_type;



    match_context()

      : results_ptr_(0)

      , prev_context_(0)

      , next_ptr_(0)

      , traits_(0)

    {

    }



    // pointer to the current match results, passed to actions as a parameter.

    match_results<BidiIter> *results_ptr_;



    // The previous match context, if this match_context corresponds to a nested regex invocation

    match_context<BidiIter> *prev_context_;



    // If this is a nested match, the "next" sub-expression to execute after the nested match

    matchable<BidiIter> const *next_ptr_;



    // A pointer to the current traits object

    detail::traits<char_type> const *traits_;

};



///////////////////////////////////////////////////////////////////////////////

// attr_context

//

struct attr_context

{

    // Slots for holding type-erased pointers to attributes

    void const **attr_slots_;



    // The previous attr context, if one exists

    attr_context *prev_attr_context_;

};



///////////////////////////////////////////////////////////////////////////////

// match_flags

//

struct match_flags

{

    bool match_all_;

    bool match_prev_avail_;

    bool match_bol_;

    bool match_eol_;

    bool match_not_bow_;

    bool match_not_eow_;

    bool match_not_null_;

    bool match_continuous_;

    bool match_partial_;



    explicit match_flags(regex_constants::match_flag_type flags)

      : match_all_(false)

      , match_prev_avail_(0 != (flags & regex_constants::match_prev_avail))

      , match_bol_(match_prev_avail_ || 0 == (flags & regex_constants::match_not_bol))

      , match_eol_(0 == (flags & regex_constants::match_not_eol))

      , match_not_bow_(!match_prev_avail_ && 0 != (flags & regex_constants::match_not_bow))

      , match_not_eow_(0 != (flags & regex_constants::match_not_eow))

      , match_not_null_(0 != (flags & regex_constants::match_not_null))

      , match_continuous_(0 != (flags & regex_constants::match_continuous))

      , match_partial_(0 != (flags & regex_constants::match_partial))

    {

    }

};



///////////////////////////////////////////////////////////////////////////////

// match_state

//

template<typename BidiIter>

struct match_state

  : noncopyable

{

    typedef BidiIter iterator;

    typedef core_access<BidiIter> access;

    typedef detail::match_context<BidiIter> match_context;

    typedef detail::results_extras<BidiIter> results_extras;

    typedef detail::regex_impl<BidiIter> regex_impl;

    typedef detail::matchable<BidiIter> matchable;

    typedef xpressive::match_results<BidiIter> match_results;

    typedef detail::sub_match_impl<BidiIter> sub_match_impl;

    typedef detail::actionable actionable;



    BidiIter cur_;

    sub_match_impl *sub_matches_;

    std::size_t mark_count_;

    BidiIter begin_;

    BidiIter end_;



    match_flags flags_;

    bool found_partial_match_;



    match_context context_;

    results_extras *extras_;

    actionable action_list_;

    actionable const **action_list_tail_;

    action_args_type *action_args_;

    attr_context attr_context_;



    ///////////////////////////////////////////////////////////////////////////////

    //

    match_state

    (

        BidiIter begin

      , BidiIter end

      , match_results &what

      , regex_impl const &impl

      , regex_constants::match_flag_type flags

    )

      : cur_(begin)

      , sub_matches_(0)

      , mark_count_(0)

      , begin_(begin)

      , end_(end)

      , flags_(flags)

      , found_partial_match_(false)

      , context_() // zero-initializes the fields of context_

      , extras_(&core_access<BidiIter>::get_extras(what))

      , action_list_()

      , action_list_tail_(&action_list_.next)

      , action_args_(&core_access<BidiIter>::get_action_args(what))

      , attr_context_() // zero-initializes the fields of attr_context_

    {

        // reclaim any cached memory in the match_results struct

        this->extras_->sub_match_stack_.unwind();



        // initialize the context_ struct

        this->init_(impl, what);



        // move all the nested match_results structs into the match_results cache

        this->extras_->results_cache_.reclaim_all(access::get_nested_results(what));

    }



    ///////////////////////////////////////////////////////////////////////////////

    // reset

    void reset(match_results &what, regex_impl const &impl)

    {

        this->extras_ = &core_access<BidiIter>::get_extras(what);

        this->action_list_.next = 0;

        this->action_list_tail_ = &action_list_.next;

        this->action_args_ = &core_access<BidiIter>::get_action_args(what);

        this->attr_context_ = attr_context();

        this->context_.prev_context_ = 0;

        this->found_partial_match_ = false;

        this->extras_->sub_match_stack_.unwind();

        this->init_(impl, what);

        this->extras_->results_cache_.reclaim_all(access::get_nested_results(what));

    }



    ///////////////////////////////////////////////////////////////////////////////

    // push_context

    //  called to prepare the state object for a regex match

    match_context push_context(regex_impl const &impl, matchable const &next, match_context &prev)

    {

        // save state

        match_context context = this->context_;



        // create a new nested match_results for this regex

        nested_results<BidiIter> &nested = access::get_nested_results(*context.results_ptr_);

        match_results &what = this->extras_->results_cache_.append_new(nested);



        // (re)initialize the match context

        this->init_(impl, what);



        // create a linked list of match_context structs

        this->context_.prev_context_ = &prev;

        this->context_.next_ptr_ = &next;



        // record the start of the zero-th sub-match

        this->sub_matches_[0].begin_ = this->cur_;



        return context;

    }



    ///////////////////////////////////////////////////////////////////////////////

    // pop_context

    //  called after a nested match failed to restore the context

    bool pop_context(regex_impl const &impl, bool success)

    {

        match_context &context = *this->context_.prev_context_;

        if(!success)

        {

            match_results &what = *context.results_ptr_;

            this->uninit_(impl, what);



            // send the match_results struct back to the cache

            nested_results<BidiIter> &nested = access::get_nested_results(what);

            this->extras_->results_cache_.reclaim_last(nested);

        }



        // restore the state

        this->context_ = context;

        match_results &results = *this->context_.results_ptr_;

        this->sub_matches_ = access::get_sub_matches(access::get_sub_match_vector(results));

        this->mark_count_ = results.size();

        return success;

    }



    ///////////////////////////////////////////////////////////////////////////////

    // swap_context

    void swap_context(match_context &context)

    {

        std::swap(this->context_, context);

        match_results &results = *this->context_.results_ptr_;

        this->sub_matches_ = access::get_sub_matches(access::get_sub_match_vector(results));

        this->mark_count_ = results.size();

    }



    // beginning of buffer

    bool bos() const

    {

        return this->cur_ == this->begin_;

    }



    // end of buffer

    bool eos()

    {

        return this->cur_ == this->end_ && this->found_partial_match();

    }



    // is this the regex that is currently executing?

    bool is_active_regex(regex_impl const &impl) const

    {

        return impl.xpr_.get() == this->context_.results_ptr_->regex_id();

    }



    // fetch the n-th sub_match

    sub_match_impl &sub_match(int n)

    {

        return this->sub_matches_[n];

    }



    // called when a partial match has succeeded

    void set_partial_match()

    {

        sub_match_impl &sub0 = this->sub_match(0);

        sub0.first = sub0.begin_;

        sub0.second = this->end_;

        sub0.matched = false;

    }



    template<typename Traits>

    Traits const &get_traits() const

    {

        return static_cast<traits_holder<Traits> const *>(this->context_.traits_)->traits();

    }



private:



    void init_(regex_impl const &impl, match_results &what)

    {

        regex_id_type const id = impl.xpr_.get();

        std::size_t const total_mark_count = impl.mark_count_ + impl.hidden_mark_count_ + 1;



        // initialize the context and the sub_match vector

        this->context_.results_ptr_ = &what;

        this->context_.traits_ = impl.traits_.get();

        this->mark_count_ = impl.mark_count_ + 1;

        this->sub_matches_ = this->extras_->sub_match_stack_.push_sequence(total_mark_count);

        this->sub_matches_ += impl.hidden_mark_count_;



        // initialize the match_results struct

        access::init_match_results(what, id, impl.traits_, this->sub_matches_, this->mark_count_, impl.named_marks_);

    }



    void uninit_(regex_impl const &impl, match_results &)

    {

        extras_->sub_match_stack_.unwind_to(this->sub_matches_ - impl.hidden_mark_count_);

    }



    bool found_partial_match()

    {

        this->found_partial_match_ = true;

        return true;

    }

};



///////////////////////////////////////////////////////////////////////////////

// memento

//

template<typename BidiIter>

struct memento

{

    sub_match_impl<BidiIter> *old_sub_matches_;

    std::size_t nested_results_count_;

    actionable const **action_list_tail_;

    attr_context attr_context_;

};



///////////////////////////////////////////////////////////////////////////////

// save_sub_matches

//

template<typename BidiIter>

inline memento<BidiIter> save_sub_matches(match_state<BidiIter> &state)

{

    memento<BidiIter> mem =

    {

        state.extras_->sub_match_stack_.push_sequence(state.mark_count_, no_fill)

      , state.context_.results_ptr_->nested_results().size()

      , state.action_list_tail_

      , state.attr_context_

    };

    std::copy(state.sub_matches_, state.sub_matches_ + state.mark_count_, mem.old_sub_matches_);

    return mem;

}



///////////////////////////////////////////////////////////////////////////////

// restore_sub_matches

//

template<typename BidiIter>

inline void restore_sub_matches(memento<BidiIter> const &mem, match_state<BidiIter> &state)

{

    typedef core_access<BidiIter> access;

    nested_results<BidiIter> &nested = access::get_nested_results(*state.context_.results_ptr_);

    std::size_t count = nested.size() - mem.nested_results_count_;

    state.extras_->results_cache_.reclaim_last_n(nested, count);

    std::copy(mem.old_sub_matches_, mem.old_sub_matches_ + state.mark_count_, state.sub_matches_);

    state.extras_->sub_match_stack_.unwind_to(mem.old_sub_matches_);

    state.attr_context_ = mem.attr_context_;

    state.action_list_tail_ = mem.action_list_tail_;

    *state.action_list_tail_ = 0;

}



///////////////////////////////////////////////////////////////////////////////

// reclaim_sub_matches

//

template<typename BidiIter>

inline void reclaim_sub_matches(memento<BidiIter> const &mem, match_state<BidiIter> &state, bool success)

{

    std::size_t count = state.context_.results_ptr_->nested_results().size() - mem.nested_results_count_;

    if(count == 0)

    {

        state.extras_->sub_match_stack_.unwind_to(mem.old_sub_matches_);

    }

    // else we have we must orphan this block of backrefs because we are using the stack

    // space above it.



    if(!success)

    {

        state.attr_context_ = mem.attr_context_;

        state.action_list_tail_ = mem.action_list_tail_;

        *state.action_list_tail_ = 0;

    }

}



///////////////////////////////////////////////////////////////////////////////

// traits_cast

//

template<typename Traits, typename BidiIter>

inline Traits const &traits_cast(match_state<BidiIter> const &state)

{

    return state.template get_traits<Traits>();

}



}}} // namespace boost::xpressive::detail



#endif

