/*
 *
 * Copyright (c) 2003
 * John Maddock
 *
 * Use, modification and distribution are subject to 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)
 *
 */

/*
 *   LOCATION:    see http://www.boost.org for most recent version.
 *   FILE         regex_iterator.hpp
 *   VERSION      see <boost/version.hpp>
 *   DESCRIPTION: Provides regex_iterator implementation.
 */

#ifndef BOOST_REGEX_V5_REGEX_ITERATOR_HPP
#define BOOST_REGEX_V5_REGEX_ITERATOR_HPP

#include <memory>

namespace boost {

template <class BidirectionalIterator,
          class charT,
          class traits>
class regex_iterator_implementation
{
    typedef basic_regex<charT, traits> regex_type;

    match_results<BidirectionalIterator> what;  // current match
    BidirectionalIterator                base;  // start of sequence
    BidirectionalIterator                end;   // end of sequence
    const regex_type                     re;   // the expression
    match_flag_type                      flags; // flags for matching

  public:
    regex_iterator_implementation(const regex_type* p, BidirectionalIterator last, match_flag_type f)
        : base(), end(last), re(*p), flags(f) {}
    regex_iterator_implementation(const regex_iterator_implementation& other)
        :what(other.what), base(other.base), end(other.end), re(other.re), flags(other.flags) {}
    bool
    init(BidirectionalIterator first)
    {
        base = first;
        return regex_search(first, end, what, re, flags);
    }
    bool
    compare(const regex_iterator_implementation& that)
    {
        if (this == &that)
        {
            return true;
        }

        return (&re.get_data() == &that.re.get_data()) && (end == that.end) && (flags == that.flags) && (what[0].first == that.what[0].first) && (what[0].second == that.what[0].second);
    }
    const match_results<BidirectionalIterator>&
    get()
    {
        return what;
    }
    bool
    next()
    {
        //if(what.prefix().first != what[0].second)
        //   flags |= match_prev_avail;
        BidirectionalIterator next_start = what[0].second;
        match_flag_type f(flags);

        if (!what.length() || (f & regex_constants::match_posix))
        {
            f |= regex_constants::match_not_initial_null;
        }

        //if(base != next_start)
        //   f |= regex_constants::match_not_bob;
        bool result = regex_search(next_start, end, what, re, f, base);

        if (result)
        {
            what.set_base(base);
        }

        return result;
    }
  private:
    regex_iterator_implementation&
    operator=(const regex_iterator_implementation&);
};

template <class BidirectionalIterator,
          class charT = typename std::iterator_traits<BidirectionalIterator>::value_type,
          class traits = regex_traits<charT> >
class regex_iterator
{
  private:
    typedef regex_iterator_implementation<BidirectionalIterator, charT, traits> impl;
    typedef std::shared_ptr<impl> pimpl;
  public:
    typedef          basic_regex<charT, traits>                   regex_type;
    typedef          match_results<BidirectionalIterator>                    value_type;
    typedef typename std::iterator_traits<BidirectionalIterator>::difference_type
    difference_type;
    typedef          const value_type*                                       pointer;
    typedef          const value_type&                                       reference;
    typedef          std::forward_iterator_tag                               iterator_category;

    regex_iterator() {}
    regex_iterator(BidirectionalIterator a, BidirectionalIterator b,
                   const regex_type& re,
                   match_flag_type m = match_default)
        : pdata(new impl(&re, b, m))
    {
        if (!pdata->init(a))
        {
            pdata.reset();
        }
    }
    regex_iterator(const regex_iterator& that)
        : pdata(that.pdata) {}
    regex_iterator&
    operator=(const regex_iterator& that)
    {
        pdata = that.pdata;
        return *this;
    }
    bool
    operator==(const regex_iterator& that)const
    {
        if ((pdata.get() == 0) || (that.pdata.get() == 0))
        {
            return pdata.get() == that.pdata.get();
        }

        return pdata->compare(*(that.pdata.get()));
    }
    bool
    operator!=(const regex_iterator& that)const
    {
        return !(*this == that);
    }
    const value_type&
    operator*()const
    {
        return pdata->get();
    }
    const value_type*
    operator->()const
    {
        return &(pdata->get());
    }
    regex_iterator&
    operator++()
    {
        cow();

        if (0 == pdata->next())
        {
            pdata.reset();
        }

        return *this;
    }
    regex_iterator
    operator++(int)
    {
        regex_iterator result(*this);
        ++(*this);
        return result;
    }
  private:

    pimpl pdata;

    void
    cow()
    {
        // copy-on-write
        if (pdata.get() && (pdata.use_count() > 1))
        {
            pdata.reset(new impl(*(pdata.get())));
        }
    }
};

typedef regex_iterator<const char*> cregex_iterator;
typedef regex_iterator<std::string::const_iterator> sregex_iterator;
#ifndef BOOST_NO_WREGEX
typedef regex_iterator<const wchar_t*> wcregex_iterator;
typedef regex_iterator<std::wstring::const_iterator> wsregex_iterator;
#endif

// make_regex_iterator:
template <class charT, class traits>
inline regex_iterator<const charT*, charT, traits>
make_regex_iterator(const charT* p, const basic_regex<charT, traits>& e, regex_constants::match_flag_type m = regex_constants::match_default)
{
    return regex_iterator<const charT*, charT, traits>(p, p+traits::length(p), e, m);
}
template <class charT, class traits, class ST, class SA>
inline regex_iterator<typename std::basic_string<charT, ST, SA>::const_iterator, charT, traits>
make_regex_iterator(const std::basic_string<charT, ST, SA>& p, const basic_regex<charT, traits>& e, regex_constants::match_flag_type m = regex_constants::match_default)
{
    return regex_iterator<typename std::basic_string<charT, ST, SA>::const_iterator, charT, traits>(p.begin(), p.end(), e, m);
}

} // namespace boost

#endif // BOOST_REGEX_V5_REGEX_ITERATOR_HPP
