/*

 *

 * Copyright (c) 1998-2002

 * 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_split.hpp

  *   VERSION      see <boost/version.hpp>

  *   DESCRIPTION: Implements regex_split and associated functions.

  *                Note this is an internal header file included

  *                by regex.hpp, do not include on its own.

  */



#ifndef BOOST_REGEX_SPLIT_HPP

#define BOOST_REGEX_SPLIT_HPP



namespace boost{



#ifdef BOOST_MSVC

#pragma warning(push)

#pragma warning(disable: 4103)

#endif

#ifdef BOOST_HAS_ABI_HEADERS

#  include BOOST_ABI_PREFIX

#endif

#ifdef BOOST_MSVC

#pragma warning(pop)

#endif



#ifdef BOOST_MSVC

#  pragma warning(push)

#  pragma warning(disable: 4800)

#endif



namespace re_detail{



template <class charT>

const basic_regex<charT>& get_default_expression(charT)

{

   static const charT expression_text[4] = { '\\', 's', '+', '\00', };

   static const basic_regex<charT> e(expression_text);

   return e;

}



template <class OutputIterator, class charT, class Traits1, class Alloc1>

class split_pred

{

   typedef std::basic_string<charT, Traits1, Alloc1> string_type;

   typedef typename string_type::const_iterator iterator_type;

   iterator_type* p_last;

   OutputIterator* p_out;

   std::size_t* p_max;

   std::size_t initial_max;

public:

   split_pred(iterator_type* a, OutputIterator* b, std::size_t* c)

      : p_last(a), p_out(b), p_max(c), initial_max(*c) {}



   bool operator()(const match_results<iterator_type>& what);

};



template <class OutputIterator, class charT, class Traits1, class Alloc1>

bool split_pred<OutputIterator, charT, Traits1, Alloc1>::operator()

   (const match_results<iterator_type>& what)

{

   *p_last = what[0].second;

   if(what.size() > 1)

   {

      // output sub-expressions only:

      for(unsigned i = 1; i < what.size(); ++i)

      {

         *(*p_out) = what.str(i);

         ++(*p_out);

         if(0 == --*p_max) return false;

      }

      return *p_max != 0;

   }

   else

   {

      // output $` only if it's not-null or not at the start of the input:

      const sub_match<iterator_type>& sub = what[-1];

      if((sub.first != sub.second) || (*p_max != initial_max))

      {

         *(*p_out) = sub.str();

         ++(*p_out);

         return --*p_max;

      }

   }

   //

   // initial null, do nothing:

   return true;

}



} // namespace re_detail



template <class OutputIterator, class charT, class Traits1, class Alloc1, class Traits2>

std::size_t regex_split(OutputIterator out,

                   std::basic_string<charT, Traits1, Alloc1>& s, 

                   const basic_regex<charT, Traits2>& e,

                   match_flag_type flags,

                   std::size_t max_split)

{

   typedef typename std::basic_string<charT, Traits1, Alloc1>::const_iterator  ci_t;

   typedef typename match_results<ci_t>::allocator_type                        match_allocator;

   ci_t last = s.begin();

   std::size_t init_size = max_split;

   re_detail::split_pred<OutputIterator, charT, Traits1, Alloc1> pred(&last, &out, &max_split);

   ci_t i, j;

   i = s.begin();

   j = s.end();

   regex_grep(pred, i, j, e, flags);

   //

   // if there is still input left, do a final push as long as max_split

   // is not exhausted, and we're not splitting sub-expressions rather 

   // than whitespace:

   if(max_split && (last != s.end()) && (e.mark_count() == 1))

   {

      *out = std::basic_string<charT, Traits1, Alloc1>((ci_t)last, (ci_t)s.end());

      ++out;

      last = s.end();

      --max_split;

   }

   //

   // delete from the string everything that has been processed so far:

   s.erase(0, last - s.begin());

   //

   // return the number of new records pushed:

   return init_size - max_split;

}



template <class OutputIterator, class charT, class Traits1, class Alloc1, class Traits2>

inline std::size_t regex_split(OutputIterator out,

                   std::basic_string<charT, Traits1, Alloc1>& s, 

                   const basic_regex<charT, Traits2>& e,

                   match_flag_type flags = match_default)

{

   return regex_split(out, s, e, flags, UINT_MAX);

}



template <class OutputIterator, class charT, class Traits1, class Alloc1>

inline std::size_t regex_split(OutputIterator out,

                   std::basic_string<charT, Traits1, Alloc1>& s)

{

   return regex_split(out, s, re_detail::get_default_expression(charT(0)), match_default, UINT_MAX);

}



#ifdef BOOST_MSVC

#  pragma warning(pop)

#endif



#ifdef BOOST_MSVC

#pragma warning(push)

#pragma warning(disable: 4103)

#endif

#ifdef BOOST_HAS_ABI_HEADERS

#  include BOOST_ABI_SUFFIX

#endif

#ifdef BOOST_MSVC

#pragma warning(pop)

#endif



} // namespace boost



#endif





