code:
/*
 *
 * Copyright (c) 1998-2009 John Maddock
 * Copyright 2008 Eric Niebler.
 *
 * 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_format.hpp
  *   VERSION      see <boost/version.hpp>
  *   DESCRIPTION: Provides formatting output routines for search and replace
  *                operations.  Note this is an internal header file included
  *                by regex.hpp, do not include on its own.
  */

#ifndef BOOST_REGEX_FORMAT_HPP
#define BOOST_REGEX_FORMAT_HPP

#include <boost/type_traits/is_pointer.hpp>
#include <boost/type_traits/is_function.hpp>
#include <boost/type_traits/is_class.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/not.hpp>
#ifndef BOOST_NO_SFINAE
#include <boost/mpl/has_xxx.hpp>
#endif
#include <boost/ref.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

//
// Forward declaration:
//
   template <class BidiIterator, class Allocator = BOOST_DEDUCED_TYPENAME std::vector<sub_match<BidiIterator> >::allocator_type >
class match_results;

namespace BOOST_REGEX_DETAIL_NS{

//
// struct trivial_format_traits:
// defines minimum localisation support for formatting
// in the case that the actual regex traits is unavailable.
//
template <class charT>
struct trivial_format_traits
{
   typedef charT char_type;

   static std::ptrdiff_t length(const charT* p)
   {
      return global_length(p);
   }
   static charT tolower(charT c)
   {
      return ::boost::BOOST_REGEX_DETAIL_NS::global_lower(c);
   }
   static charT toupper(charT c)
   {
      return ::boost::BOOST_REGEX_DETAIL_NS::global_upper(c);
   }
   static int value(const charT c, int radix)
   {
      int result = global_value(c);
      return result >= radix ? -1 : result;
   }
   int toi(const charT*& p1, const charT* p2, int radix)const
   {
      return (int)global_toi(p1, p2, radix, *this);
   }
};

template <class OutputIterator, class Results, class traits, class ForwardIter>
class basic_regex_formatter
{
public:
   typedef typename traits::char_type char_type;
   basic_regex_formatter(OutputIterator o, const Results& r, const traits& t)
      : m_traits(t), m_results(r), m_out(o), m_position(), m_end(), m_flags(), m_state(output_copy), m_restore_state(output_copy), m_have_conditional(false) {}
   OutputIterator format(ForwardIter p1, ForwardIter p2, match_flag_type f);
   OutputIterator format(ForwardIter p1, match_flag_type f)
   {
      return format(p1, p1 + m_traits.length(p1), f);
   }
private:
   typedef typename Results::value_type sub_match_type;
   enum output_state
   {
      output_copy,
      output_next_lower,
      output_next_upper,
      output_lower,
      output_upper,
      output_none
   };

   void put(char_type c);
   void put(const sub_match_type& sub);
   void format_all();
   void format_perl();
   void format_escape();
   void format_conditional();
   void format_until_scope_end();
   bool handle_perl_verb(bool have_brace);

   inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j, const mpl::false_&)
   {
      std::vector<char_type> v(i, j);
      return (i != j) ? this->m_results.named_subexpression(&v[0], &v[0] + v.size())
         : this->m_results.named_subexpression(static_cast<const char_type*>(0), static_cast<const char_type*>(0));
   }
   inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j, const mpl::true_&)
   {
      return this->m_results.named_subexpression(i, j);
   }
   inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j)
   {
      typedef typename boost::is_convertible<ForwardIter, const char_type*>::type tag_type;
      return get_named_sub(i, j, tag_type());
   }
   inline int get_named_sub_index(ForwardIter i, ForwardIter j, const mpl::false_&)
   {
      std::vector<char_type> v(i, j);
      return (i != j) ? this->m_results.named_subexpression_index(&v[0], &v[0] + v.size())
         : this->m_results.named_subexpression_index(static_cast<const char_type*>(0), static_cast<const char_type*>(0));
   }
   inline int get_named_sub_index(ForwardIter i, ForwardIter j, const mpl::true_&)
   {
      return this->m_results.named_subexpression_index(i, j);
   }
   inline int get_named_sub_index(ForwardIter i, ForwardIter j)
   {
      typedef typename boost::is_convertible<ForwardIter, const char_type*>::type tag_type;
      return get_named_sub_index(i, j, tag_type());
   }
#ifdef BOOST_MSVC
   // msvc-8.0 issues a spurious warning on the call to std::advance here:
#pragma warning(push)
#pragma warning(disable:4244)
#endif
   inline int toi(ForwardIter& i, ForwardIter j, int base, const boost::mpl::false_&)
   {
      if(i != j)
      {
         std::vector<char_type> v(i, j);
         const char_type* start = &v[0];
         const char_type* pos = start;
         int r = (int)m_traits.toi(pos, &v[0] + v.size(), base);
         std::advance(i, pos - start);
         return r;
      }
      return -1;
   }
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
   inline int toi(ForwardIter& i, ForwardIter j, int base, const boost::mpl::true_&)
   {
      return m_traits.toi(i, j, base);
   }
   inline int toi(ForwardIter& i, ForwardIter j, int base)
   {
#if defined(_MSC_VER) && defined(__INTEL_COMPILER) && ((__INTEL_COMPILER == 9999) || (__INTEL_COMPILER == 1210))
      // Workaround for Intel support issue #656654.
      // See also https://svn.boost.org/trac/boost/ticket/6359
      return toi(i, j, base, mpl::false_());
#else
      typedef typename boost::is_convertible<ForwardIter, const char_type*&>::type tag_type;
      return toi(i, j, base, tag_type());
#endif
   }

   const traits&    m_traits;       // the traits class for localised formatting operations
   const Results&   m_results;     // the match_results being used.
   OutputIterator   m_out;         // where to send output.
   ForwardIter      m_position;  // format string, current position
   ForwardIter      m_end;       // format string end
   match_flag_type  m_flags;      // format flags to use
   output_state     m_state;      // what to do with the next character
   output_state     m_restore_state;  // what state to restore to.
   bool             m_have_conditional; // we are parsing a conditional
private:
   basic_regex_formatter(const basic_regex_formatter&);
   basic_regex_formatter& operator=(const basic_regex_formatter&);
};

template <class OutputIterator, class Results, class traits, class ForwardIter>
OutputIterator basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format(ForwardIter p1, ForwardIter p2, match_flag_type f)
{
   m_position = p1;
   m_end = p2;
   m_flags = f;
   format_all();
   return m_out;
}

template <class OutputIterator, class Results, class traits, class ForwardIter>
void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_all()
{
   // over and over:
   while(m_position != m_end)
   {
      switch(*m_position)
      {
      case '&':
         if(m_flags & ::boost::regex_constants::format_sed)
         {
            ++m_position;
            put(m_results[0]);
            break;
         }
         put(*m_position++);
         break;
      case '\\':
         format_escape();
         break;
      case '(':
         if(m_flags & boost::regex_constants::format_all)
         {
            ++m_position;
            bool have_conditional = m_have_conditional;
            m_have_conditional = false;
            format_until_scope_end();
            m_have_conditional = have_conditional;
            if(m_position == m_end)
               return;
            BOOST_ASSERT(*m_position == static_cast<char_type>(')'));
            ++m_position;  // skip the closing ')'
            break;
         }
         put(*m_position);
         ++m_position;
         break;
      case ')':
         if(m_flags & boost::regex_constants::format_all)
         {
            return;
         }
         put(*m_position);
         ++m_position;
         break;
      case ':':
         if((m_flags & boost::regex_constants::format_all) && m_have_conditional)
         {
            return;
         }
         put(*m_position);
         ++m_position;
         break;
      case '?':
         if(m_flags & boost::regex_constants::format_all)
         {
            ++m_position;
            format_conditional();
            break;
         }
         put(*m_position);
         ++m_position;
         break;
      case '$':
         if((m_flags & format_sed) == 0)
         {
            format_perl();
            break;
         }
         // not a special character:
         BOOST_FALLTHROUGH;
      default:
         put(*m_position);
         ++m_position;
         break;
      }
   }
}

template <class OutputIterator, class Results, class traits, class ForwardIter>
void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_perl()
{
   //
   // On entry *m_position points to a '$' character
   // output the information that goes with it:
   //
   BOOST_ASSERT(*m_position == '$');
   //
   // see if this is a trailing '$':
   //
   if(++m_position == m_end)
   {
      --m_position;
      put(*m_position);
      ++m_position;
      return;
   }
   //
   // OK find out what kind it is:
   //
   bool have_brace = false;
   ForwardIter save_position = m_position;
   switch(*m_position)
   {
   case '&':
      ++m_position;
      put(this->m_results[0]);
      break;
   case '`':
      ++m_position;
      put(this->m_results.prefix());
      break;
   case '\'':
      ++m_position;
      put(this->m_results.suffix());
      break;
   case '$':
      put(*m_position++);
      break;
   case '+':
      if((++m_position != m_end) && (*m_position == '{'))
      {
         ForwardIter base = ++m_position;
         while((m_position != m_end) && (*m_position != '}')) ++m_position;
         if(m_position != m_end)
         {
            // Named sub-expression:
            put(get_named_sub(base, m_position));
            ++m_position;
            break;
         }
         else
         {
            m_position = --base;
         }
      }
      put((this->m_results)[this->m_results.size() > 1 ? static_cast<int>(this->m_results.size() - 1) : 1]);
      break;
   case '{':
      have_brace = true;
      ++m_position;
      BOOST_FALLTHROUGH;
   default:
      // see if we have a number:
      {
         std::ptrdiff_t len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
         //len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
         int v = this->toi(m_position, m_position + len, 10);
         if((v < 0) || (have_brace && ((m_position == m_end) || (*m_position != '}'))))
         {
            // Look for a Perl-5.10 verb:
            if(!handle_perl_verb(have_brace))
            {
               // leave the $ as is, and carry on:
               m_position = --save_position;
               put(*m_position);
               ++m_position;
            }
            break;
         }
         // otherwise output sub v:
         put(this->m_results[v]);
         if(have_brace)
            ++m_position;
      }
   }
}

template <class OutputIterator, class Results, class traits, class ForwardIter>
bool basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::handle_perl_verb(bool have_brace)
{
   //
   // We may have a capitalised string containing a Perl action:
   //
   static const char_type MATCH[] = { 'M', 'A', 'T', 'C', 'H' };
   static const char_type PREMATCH[] = { 'P', 'R', 'E', 'M', 'A', 'T', 'C', 'H' };
   static const char_type POSTMATCH[] = { 'P', 'O', 'S', 'T', 'M', 'A', 'T', 'C', 'H' };
   static const char_type LAST_PAREN_MATCH[] = { 'L', 'A', 'S', 'T', '_', 'P', 'A', 'R', 'E', 'N', '_', 'M', 'A', 'T', 'C', 'H' };
   static const char_type LAST_SUBMATCH_RESULT[] = { 'L', 'A', 'S', 'T', '_', 'S', 'U', 'B', 'M', 'A', 'T', 'C', 'H', '_', 'R', 'E', 'S', 'U', 'L', 'T' };
   static const char_type LAST_SUBMATCH_RESULT_ALT[] = { '^', 'N' };

   if(m_position == m_end)
      return false;
   if(have_brace && (*m_position == '^'))
      ++m_position;

   std::ptrdiff_t max_len = m_end - m_position;

   if((max_len >= 5) && std::equal(m_position, m_position + 5, MATCH))
   {
      m_position += 5;
      if(have_brace)
      {
         if((m_position != m_end) && (*m_position == '}'))
            ++m_position;
         else
         {
            m_position -= 5;
            return false;
         }
      }
      put(this->m_results[0]);
      return true;
   }
   if((max_len >= 8) && std::equal(m_position, m_position + 8, PREMATCH))
   {
      m_position += 8;
      if(have_brace)
      {
         if((m_position != m_end) && (*m_position == '}'))
            ++m_position;
         else
         {
            m_position -= 8;
            return false;
         }
      }
      put(this->m_results.prefix());
      return true;
   }
   if((max_len >= 9) && std::equal(m_position, m_position + 9, POSTMATCH))
   {
      m_position += 9;
      if(have_brace)
      {
         if((m_position != m_end) && (*m_position == '}'))
            ++m_position;
         else
         {
            m_position -= 9;
            return false;
         }
      }
      put(this->m_results.suffix());
      return true;
   }
   if((max_len >= 16) && std::equal(m_position, m_position + 16, LAST_PAREN_MATCH))
   {
      m_position += 16;
      if(have_brace)
      {
         if((m_position != m_end) && (*m_position == '}'))
            ++m_position;
         else
         {
            m_position -= 16;
            return false;
         }
      }
      put((this->m_results)[this->m_results.size() > 1 ? static_cast<int>(this->m_results.size() - 1) : 1]);
      return true;
   }
   if((max_len >= 20) && std::equal(m_position, m_position + 20, LAST_SUBMATCH_RESULT))
   {
      m_position += 20;
      if(have_brace)
      {
         if((m_position != m_end) && (*m_position == '}'))
            ++m_position;
         else
         {
            m_position -= 20;
            return false;
         }
      }
      put(this->m_results.get_last_closed_paren());
      return true;
   }
   if((max_len >= 2) && std::equal(m_position, m_position + 2, LAST_SUBMATCH_RESULT_ALT))
   {
      m_position += 2;
      if(have_brace)
      {
         if((m_position != m_end) && (*m_position == '}'))
            ++m_position;
         else
         {
            m_position -= 2;
            return false;
         }
      }
      put(this->m_results.get_last_closed_paren());
      return true;
   }
   return false;
}

template <class OutputIterator, class Results, class traits, class ForwardIter>
void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_escape()
{
   // skip the escape and check for trailing escape:
   if(++m_position == m_end)
   {
      put(static_cast<char_type>('\\'));
      return;
   }
   // now switch on the escape type:
   switch(*m_position)
   {
   case 'a':
      put(static_cast<char_type>('\a'));
      ++m_position;
      break;
   case 'f':
      put(static_cast<char_type>('\f'));
      ++m_position;
      break;
   case 'n':
      put(static_cast<char_type>('\n'));
      ++m_position;
      break;
   case 'r':
      put(static_cast<char_type>('\r'));
      ++m_position;
      break;
   case 't':
      put(static_cast<char_type>('\t'));
      ++m_position;
      break;
   case 'v':
      put(static_cast<char_type>('\v'));
      ++m_position;
      break;
   case 'x':
      if(++m_position == m_end)
      {
         put(static_cast<char_type>('x'));
         return;
      }
      // maybe have \x{ddd}
      if(*m_position == static_cast<char_type>('{'))
      {
         ++m_position;
         int val = this->toi(m_position, m_end, 16);
         if(val < 0)
         {
            // invalid value treat everything as literals:
            put(static_cast<char_type>('x'));
            put(static_cast<char_type>('{'));
            return;
         }
         if((m_position == m_end) || (*m_position != static_cast<char_type>('}')))
         {
            --m_position;
            while(*m_position != static_cast<char_type>('\\'))
               --m_position;
            ++m_position;
            put(*m_position++);
            return;
         }
         ++m_position;
         put(static_cast<char_type>(val));
         return;
      }
      else
      {
         std::ptrdiff_t len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
         len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
         int val = this->toi(m_position, m_position + len, 16);
         if(val < 0)
         {
            --m_position;
            put(*m_position++);
            return;
         }
         put(static_cast<char_type>(val));
      }
      break;
   case 'c':
      if(++m_position == m_end)
      {
         --m_position;
         put(*m_position++);
         return;
      }
      put(static_cast<char_type>(*m_position++ % 32));
      break;
   case 'e':
      put(static_cast<char_type>(27));
      ++m_position;
      break;
   default:
      // see if we have a perl specific escape:
      if((m_flags & boost::regex_constants::format_sed) == 0)
      {
         bool breakout = false;
         switch(*m_position)
         {
         case 'l':
            ++m_position;
            m_restore_state = m_state;
            m_state = output_next_lower;
            breakout = true;
            break;
         case 'L':
            ++m_position;
            m_state = output_lower;
            breakout = true;
            break;
         case 'u':
            ++m_position;
            m_restore_state = m_state;
            m_state = output_next_upper;
            breakout = true;
            break;
         case 'U':
            ++m_position;
            m_state = output_upper;
            breakout = true;
            break;
         case 'E':
            ++m_position;
            m_state = output_copy;
            breakout = true;
            break;
         }
         if(breakout)
            break;
      }
      // see if we have a \n sed style backreference:
      std::ptrdiff_t len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
      len = (std::min)(static_cast<std::ptrdiff_t>(1), len);
      int v = this->toi(m_position, m_position+len, 10);
      if((v > 0) || ((v == 0) && (m_flags & ::boost::regex_constants::format_sed)))
      {
         put(m_results[v]);
         break;
      }
      else if(v == 0)
      {
         // octal ecape sequence:
         --m_position;
         len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
         len = (std::min)(static_cast<std::ptrdiff_t>(4), len);
         v = this->toi(m_position, m_position + len, 8);
         BOOST_ASSERT(v >= 0);
         put(static_cast<char_type>(v));
         break;
      }
      // Otherwise output the character "as is":
      put(*m_position++);
      break;
   }
}

template <class OutputIterator, class Results, class traits, class ForwardIter>
void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_conditional()
{
   if(m_position == m_end)
   {
      // oops trailing '?':
      put(static_cast<char_type>('?'));
      return;
   }
   int v;
   if(*m_position == '{')
   {
      ForwardIter base = m_position;
      ++m_position;
      v = this->toi(m_position, m_end, 10);
      if(v < 0)
      {
         // Try a named subexpression:
         while((m_position != m_end) && (*m_position != '}'))
            ++m_position;
         v = this->get_named_sub_index(base + 1, m_position);
      }
      if((v < 0) || (*m_position != '}'))
      {
         m_position = base;
         // oops trailing '?':
         put(static_cast<char_type>('?'));
         return;
      }
      // Skip trailing '}':
      ++m_position;
   }
   else
   {
      std::ptrdiff_t len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end);
      len = (std::min)(static_cast<std::ptrdiff_t>(2), len);
      v = this->toi(m_position, m_position + len, 10);
   }
   if(v < 0)
   {
      // oops not a number:
      put(static_cast<char_type>('?'));
      return;
   }

   // output varies depending upon whether sub-expression v matched or not:
   if(m_results[v].matched)
   {
      m_have_conditional = true;
      format_all();
      m_have_conditional = false;
      if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
      {
         // skip the ':':
         ++m_position;
         // save output state, then turn it off:
         output_state saved_state = m_state;
         m_state = output_none;
         // format the rest of this scope:
         format_until_scope_end();
         // restore output state:
         m_state = saved_state;
      }
   }
   else
   {
      // save output state, then turn it off:
      output_state saved_state = m_state;
      m_state = output_none;
      // format until ':' or ')':
      m_have_conditional = true;
      format_all();
      m_have_conditional = false;
      // restore state:
      m_state = saved_state;
      if((m_position != m_end) && (*m_position == static_cast<char_type>(':')))
      {
         // skip the ':':
         ++m_position;
         // format the rest of this scope:
         format_until_scope_end();
      }
   }
}

template <class OutputIterator, class Results, class traits, class ForwardIter>
void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::format_until_scope_end()
{
   do
   {
      format_all();
      if((m_position == m_end) || (*m_position == static_cast<char_type>(')')))
         return;
      put(*m_position++);
   }while(m_position != m_end);
}

template <class OutputIterator, class Results, class traits, class ForwardIter>
void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::put(char_type c)
{
   // write a single character to output
   // according to which case translation mode we are in:
   switch(this->m_state)
   {
   case output_none:
      return;
   case output_next_lower:
      c = m_traits.tolower(c);
      this->m_state = m_restore_state;
      break;
   case output_next_upper:
      c = m_traits.toupper(c);
      this->m_state = m_restore_state;
      break;
   case output_lower:
      c = m_traits.tolower(c);
      break;
   case output_upper:
      c = m_traits.toupper(c);
      break;
   default:
      break;
   }
   *m_out = c;
   ++m_out;
}

template <class OutputIterator, class Results, class traits, class ForwardIter>
void basic_regex_formatter<OutputIterator, Results, traits, ForwardIter>::put(const sub_match_type& sub)
{
   typedef typename sub_match_type::iterator iterator_type;
   iterator_type i = sub.first;
   while(i != sub.second)
   {
      put(*i);
      ++i;
   }
}

template <class S>
class string_out_iterator
#ifndef BOOST_NO_STD_ITERATOR
   : public std::iterator<std::output_iterator_tag, typename S::value_type>
#endif
{
   S* out;
public:
   string_out_iterator(S& s) : out(&s) {}
   string_out_iterator& operator++() { return *this; }
   string_out_iterator& operator++(int) { return *this; }
   string_out_iterator& operator*() { return *this; }
   string_out_iterator& operator=(typename S::value_type v)
   {
      out->append(1, v);
      return *this;
   }

#ifdef BOOST_NO_STD_ITERATOR
   typedef std::ptrdiff_t difference_type;
   typedef typename S::value_type value_type;
   typedef value_type* pointer;
   typedef value_type& reference;
   typedef std::output_iterator_tag iterator_category;
#endif
};

template <class OutputIterator, class Iterator, class Alloc, class ForwardIter, class traits>
OutputIterator regex_format_imp(OutputIterator out,
                          const match_results<Iterator, Alloc>& m,
                          ForwardIter p1, ForwardIter p2,
                          match_flag_type flags,
                          const traits& t
                         )
{
   if(flags & regex_constants::format_literal)
   {
      return BOOST_REGEX_DETAIL_NS::copy(p1, p2, out);
   }

   BOOST_REGEX_DETAIL_NS::basic_regex_formatter<
      OutputIterator,
      match_results<Iterator, Alloc>,
      traits, ForwardIter> f(out, m, t);
   return f.format(p1, p2, flags);
}

#ifndef BOOST_NO_SFINAE

BOOST_MPL_HAS_XXX_TRAIT_DEF(const_iterator)

struct any_type
{
   template <class T>
   any_type(const T&);
   template <class T, class U>
   any_type(const T&, const U&);
   template <class T, class U, class V>
   any_type(const T&, const U&, const V&);
};
typedef char no_type;
typedef char (&unary_type)[2];
typedef char (&binary_type)[3];
typedef char (&ternary_type)[4];

no_type check_is_formatter(unary_type, binary_type, ternary_type);
template<typename T>
unary_type check_is_formatter(T const &, binary_type, ternary_type);
template<typename T>
binary_type check_is_formatter(unary_type, T const &, ternary_type);
template<typename T, typename U>
binary_type check_is_formatter(T const &, U const &, ternary_type);
template<typename T>
ternary_type check_is_formatter(unary_type, binary_type, T const &);
template<typename T, typename U>
ternary_type check_is_formatter(T const &, binary_type, U const &);
template<typename T, typename U>
ternary_type check_is_formatter(unary_type, T const &, U const &);
template<typename T, typename U, typename V>
ternary_type check_is_formatter(T const &, U const &, V const &);

struct unary_binary_ternary
{
    typedef unary_type (*unary_fun)(any_type);
    typedef binary_type (*binary_fun)(any_type, any_type);
    typedef ternary_type (*ternary_fun)(any_type, any_type, any_type);
    operator unary_fun();
    operator binary_fun();
    operator ternary_fun();
};

template<typename Formatter, bool IsFunction = boost::is_function<Formatter>::value>
struct formatter_wrapper
  : Formatter
  , unary_binary_ternary
{
   formatter_wrapper(){}
};

template<typename Formatter>
struct formatter_wrapper<Formatter, true>
  : unary_binary_ternary
{
    operator Formatter *();
};

template<typename Formatter>
struct formatter_wrapper<Formatter *, false>
  : unary_binary_ternary
{
    operator Formatter *();
};

template <class F, class M, class O>
struct format_traits_imp
{
private:
   //
   // F must be a pointer, a function, or a class with a function call operator:
   //
   BOOST_STATIC_ASSERT((::boost::is_pointer<F>::value || ::boost::is_function<F>::value || ::boost::is_class<F>::value));
   static formatter_wrapper<typename unwrap_reference<F>::type> f;
   static M m;
   static O out;
   static boost::regex_constants::match_flag_type flags;
public:
   BOOST_STATIC_CONSTANT(int, value = sizeof(check_is_formatter(f(m), f(m, out), f(m, out, flags))));
};

template <class F, class M, class O>
struct format_traits
{
public:
   //
   // Type is mpl::int_<N> where N is one of:
   //
   // 0 : F is a pointer to a presumably null-terminated string.
   // 1 : F is a character-container such as a std::string.
   // 2 : F is a Unary Functor.
   // 3 : F is a Binary Functor.
   // 4 : F is a Ternary Functor.
   //
   typedef typename boost::mpl::if_<
      boost::mpl::and_<boost::is_pointer<F>, boost::mpl::not_<boost::is_function<typename boost::remove_pointer<F>::type> > >,
      boost::mpl::int_<0>,
      typename boost::mpl::if_<
         has_const_iterator<F>,
         boost::mpl::int_<1>,
         boost::mpl::int_<format_traits_imp<F, M, O>::value>
      >::type
   >::type type;
   //
   // This static assertion will fail if the functor passed does not accept
   // the same type of arguments passed.
   //
   BOOST_STATIC_ASSERT( boost::is_class<F>::value && !has_const_iterator<F>::value ? (type::value > 1) : true);
};

#else // BOOST_NO_SFINAE

template <class F, class M, class O>
struct format_traits
{
public:
   //
   // Type is mpl::int_<N> where N is one of:
   //
   // 0 : F is a pointer to a presumably null-terminated string.
   // 1 : F is a character-container such as a std::string.
   //
   // Other options such as F being a Functor are not supported without
   // SFINAE support.
   //
   typedef typename boost::mpl::if_<
      boost::is_pointer<F>,
      boost::mpl::int_<0>,
      boost::mpl::int_<1>
   >::type type;
};

#endif // BOOST_NO_SFINAE

template <class Base, class Match>
struct format_functor3
{
   format_functor3(Base b) : func(b) {}
   template <class OutputIter>
   OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f)
   {
      return boost::unwrap_ref(func)(m, i, f);
   }
   template <class OutputIter, class Traits>
   OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&)
   {
      return (*this)(m, i, f);
   }
private:
   Base func;
   format_functor3(const format_functor3&);
   format_functor3& operator=(const format_functor3&);
};

template <class Base, class Match>
struct format_functor2
{
   format_functor2(Base b) : func(b) {}
   template <class OutputIter>
   OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type /*f*/)
   {
      return boost::unwrap_ref(func)(m, i);
   }
   template <class OutputIter, class Traits>
   OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&)
   {
      return (*this)(m, i, f);
   }
private:
   Base func;
   format_functor2(const format_functor2&);
   format_functor2& operator=(const format_functor2&);
};

template <class Base, class Match>
struct format_functor1
{
   format_functor1(Base b) : func(b) {}

   template <class S, class OutputIter>
   OutputIter do_format_string(const S& s, OutputIter i)
   {
      return BOOST_REGEX_DETAIL_NS::copy(s.begin(), s.end(), i);
   }
   template <class S, class OutputIter>
   inline OutputIter do_format_string(const S* s, OutputIter i)
   {
      while(s && *s)
      {
         *i = *s;
         ++i;
         ++s;
      }
      return i;
   }
   template <class OutputIter>
   OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type /*f*/)
   {
      return do_format_string(boost::unwrap_ref(func)(m), i);
   }
   template <class OutputIter, class Traits>
   OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&)
   {
      return (*this)(m, i, f);
   }
private:
   Base func;
   format_functor1(const format_functor1&);
   format_functor1& operator=(const format_functor1&);
};

template <class charT, class Match, class Traits>
struct format_functor_c_string
{
   format_functor_c_string(const charT* ps) : func(ps) {}

   template <class OutputIter>
   OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits& t = Traits())
   {
      //typedef typename Match::char_type char_type;
      const charT* end = func;
      while(*end) ++end;
      return regex_format_imp(i, m, func, end, f, t);
   }
private:
   const charT* func;
   format_functor_c_string(const format_functor_c_string&);
   format_functor_c_string& operator=(const format_functor_c_string&);
};

template <class Container, class Match, class Traits>
struct format_functor_container
{
   format_functor_container(const Container& c) : func(c) {}

   template <class OutputIter>
   OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits& t = Traits())
   {
      //typedef typename Match::char_type char_type;
      return BOOST_REGEX_DETAIL_NS::regex_format_imp(i, m, func.begin(), func.end(), f, t);
   }
private:
   const Container& func;
   format_functor_container(const format_functor_container&);
   format_functor_container& operator=(const format_functor_container&);
};

template <class Func, class Match, class OutputIterator, class Traits = BOOST_REGEX_DETAIL_NS::trivial_format_traits<typename Match::char_type> >
struct compute_functor_type
{
   typedef typename format_traits<Func, Match, OutputIterator>::type tag;
   typedef typename boost::remove_cv< typename boost::remove_pointer<Func>::type>::type maybe_char_type;

   typedef typename mpl::if_<
      ::boost::is_same<tag, mpl::int_<0> >, format_functor_c_string<maybe_char_type, Match, Traits>,
      typename mpl::if_<
         ::boost::is_same<tag, mpl::int_<1> >, format_functor_container<Func, Match, Traits>,
         typename mpl::if_<
            ::boost::is_same<tag, mpl::int_<2> >, format_functor1<Func, Match>,
            typename mpl::if_<
               ::boost::is_same<tag, mpl::int_<3> >, format_functor2<Func, Match>,
               format_functor3<Func, Match>
            >::type
         >::type
      >::type
   >::type type;
};

} // namespace BOOST_REGEX_DETAIL_NS

template <class OutputIterator, class Iterator, class Allocator, class Functor>
inline OutputIterator regex_format(OutputIterator out,
                          const match_results<Iterator, Allocator>& m,
                          Functor fmt,
                          match_flag_type flags = format_all
                         )
{
   return m.format(out, fmt, flags);
}

template <class Iterator, class Allocator, class Functor>
inline std::basic_string<typename match_results<Iterator, Allocator>::char_type> regex_format(const match_results<Iterator, Allocator>& m,
                                      Functor fmt,
                                      match_flag_type flags = format_all)
{
   return m.format(fmt, flags);
}

#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  // BOOST_REGEX_FORMAT_HPP


code:
//  Copyright Neil Groves 2009. Use, modification and
//  distribution is 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)
//
//
// For more information, see http://www.boost.org/libs/range/
//
#ifndef BOOST_RANGE_ALGORITHM_REMOVE_COPY_IF_HPP_INCLUDED
#define BOOST_RANGE_ALGORITHM_REMOVE_COPY_IF_HPP_INCLUDED

#include <boost/concept_check.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/concepts.hpp>
#include <algorithm>

namespace boost
{
    /// \brief template function remove_copy_if
    ///
    /// range-based version of the remove_copy_if std algorithm
    ///
    /// \pre SinglePassRange is a model of the SinglePassRangeConcept
    /// \pre OutputIterator is a model of the OutputIteratorConcept
    /// \pre Predicate is a model of the PredicateConcept
    /// \pre InputIterator's value type is convertible to Predicate's argument type
    /// \pre out_it is not an iterator in the range rng
    template< class SinglePassRange, class OutputIterator, class Predicate >
    inline OutputIterator
    remove_copy_if(const SinglePassRange& rng, OutputIterator out_it, Predicate pred)
    {
        BOOST_RANGE_CONCEPT_ASSERT(( SinglePassRangeConcept<const SinglePassRange> ));
        return std::remove_copy_if(boost::begin(rng), boost::end(rng), out_it, pred);
    }
}

#endif // include guard

license: mit


code:
/*=============================================================================
    Copyright (c) 2001-2011 Joel de Guzman
    Copyright (c) 2006 Dan Marsden

    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_PP_IS_ITERATING
#if !defined(FUSION_ZIP_HPP_20060125_2058)
#define FUSION_ZIP_HPP_20060125_2058

#include <boost/fusion/view/zip_view.hpp>
#include <boost/fusion/adapted/mpl.hpp>
#include <boost/fusion/container/vector.hpp>
#include <boost/fusion/container/vector/convert.hpp>
#include <boost/fusion/support/detail/pp_round.hpp>
#include <boost/type_traits/add_reference.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/iteration/iterate.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/mpl/placeholders.hpp>

#if !defined(FUSION_MAX_ZIP_SEQUENCES)
#define FUSION_MAX_ZIP_SEQUENCES 10
#endif

#define FUSION_MAX_ZIP_SEQUENCES_STR BOOST_PP_STRINGIZE(BOOST_FUSION_PP_ROUND_UP(FUSION_MAX_ZIP_SEQUENCES))

#if !defined(BOOST_FUSION_DONT_USE_PREPROCESSED_FILES)
#include <boost/fusion/algorithm/transformation/detail/preprocessed/zip.hpp>
#else
#if defined(__WAVE__) && defined(BOOST_FUSION_CREATE_PREPROCESSED_FILES)
#pragma wave option(preserve: 2, line: 0, output: "detail/preprocessed/zip" FUSION_MAX_ZIP_SEQUENCES_STR ".hpp")
#endif

/*=============================================================================
    Copyright (c) 2001-2011 Joel de Guzman
    Copyright (c) 2006 Dan Marsden

    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)

    This is an auto-generated file. Do not edit!
==============================================================================*/

#if defined(__WAVE__) && defined(BOOST_FUSION_CREATE_PREPROCESSED_FILES)
#pragma wave option(preserve: 1)
#endif

namespace boost { namespace fusion
{
    struct void_;

    namespace result_of
    {
        template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(BOOST_PP_INC(FUSION_MAX_ZIP_SEQUENCES), typename T, fusion::void_)>
        struct zip;
    }

#define FUSION_TEXT(z, n, text) , text

#define BOOST_PP_FILENAME_1 \
    <boost/fusion/algorithm/transformation/zip.hpp>
#define BOOST_PP_ITERATION_LIMITS (2, FUSION_MAX_ZIP_SEQUENCES)
#include BOOST_PP_ITERATE()

#undef FUSION_TEXT

}}

#if defined(__WAVE__) && defined(BOOST_FUSION_CREATE_PREPROCESSED_FILES)
#pragma wave option(output: null)
#endif

#endif // BOOST_FUSION_DONT_USE_PREPROCESSED_FILES

#endif

#else

#define ZIP_ITERATION BOOST_PP_ITERATION()

    namespace result_of
    {
        template< BOOST_PP_ENUM_PARAMS(ZIP_ITERATION, typename T) >
        struct zip< BOOST_PP_ENUM_PARAMS(ZIP_ITERATION, T)
                    BOOST_PP_REPEAT_FROM_TO(BOOST_PP_DEC(ZIP_ITERATION), FUSION_MAX_ZIP_SEQUENCES, FUSION_TEXT, void_)
        >
        {
            typedef mpl::vector< BOOST_PP_ENUM_PARAMS(ZIP_ITERATION, T) > sequences;
            typedef typename mpl::transform<sequences, add_reference<mpl::_> >::type ref_params;
            typedef zip_view<typename result_of::as_vector<ref_params>::type> type;
        };
    }

#define FUSION_REF_PARAM(z, n, data) const T ## n&

    template<BOOST_PP_ENUM_PARAMS(ZIP_ITERATION, typename T)>
    BOOST_CXX14_CONSTEXPR BOOST_FUSION_GPU_ENABLED
    inline typename result_of::zip<BOOST_PP_ENUM_PARAMS(ZIP_ITERATION, const T)>::type
    zip(BOOST_PP_ENUM_BINARY_PARAMS(ZIP_ITERATION, T, const& t))
    {
        fusion::vector<BOOST_PP_ENUM(ZIP_ITERATION, FUSION_REF_PARAM, _)> seqs(
            BOOST_PP_ENUM_PARAMS(ZIP_ITERATION, t));
        return typename result_of::zip<BOOST_PP_ENUM_PARAMS(ZIP_ITERATION, const T)>::type(
            seqs);
    }

#undef FUSION_REF_PARAM
#undef ZIP_ITERATION

#endif


code:
/*=============================================================================
    Copyright (c) 2005-2013 Joel de Guzman
    Copyright (c) 2005-2006 Dan Marsden

    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)
==============================================================================*/
#if !defined(BOOST_FUSION_MAP_ITERATOR_02042013_0835)
#define BOOST_FUSION_MAP_ITERATOR_02042013_0835

#include <boost/fusion/support/config.hpp>
#include <boost/fusion/iterator/iterator_facade.hpp>
#include <boost/mpl/minus.hpp>
#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/if.hpp>
#include <boost/utility/declval.hpp>
#include <boost/type_traits/is_const.hpp>
#include <boost/type_traits/add_const.hpp>

namespace boost { namespace fusion
{
    struct random_access_traversal_tag;

    template <typename Seq, int Pos>
    struct map_iterator
        : iterator_facade<
            map_iterator<Seq, Pos>
          , typename Seq::category>
    {
        typedef Seq sequence;
        typedef mpl::int_<Pos> index;

        BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED
        map_iterator(Seq& seq)
            : seq_(seq)
        {}

        template<typename Iterator>
        struct value_of
        {
            typedef typename Iterator::sequence sequence;
            typedef typename Iterator::index index;
            typedef
                decltype(boost::declval<sequence>().get_val(index()))
            type;
        };

        template<typename Iterator>
        struct value_of_data
        {
            typedef typename Iterator::sequence sequence;
            typedef typename Iterator::index index;
            typedef
                decltype(boost::declval<sequence>().get_val(index()).second)
            type;
        };

        template<typename Iterator>
        struct key_of
        {
            typedef typename Iterator::sequence sequence;
            typedef typename Iterator::index index;
            typedef decltype(boost::declval<sequence>().get_key(index())) key_identity_type;
            typedef typename key_identity_type::type type;
        };

        template<typename Iterator>
        struct deref
        {
            typedef typename Iterator::sequence sequence;
            typedef typename Iterator::index index;
            typedef
                decltype(boost::declval<sequence>().get(index()))
            type;

            BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED
            static type
            call(Iterator const& it)
            {
                return it.seq_.get(typename Iterator::index());
            }
        };

        template<typename Iterator>
        struct deref_data
        {
            typedef typename Iterator::sequence sequence;
            typedef typename Iterator::index index;

            typedef decltype(boost::declval<sequence>().get(index()).second) second_type_;

            typedef typename
                mpl::if_<
                    is_const<sequence>
                  , typename add_const<second_type_>::type
                  , second_type_
                >::type
            second_type;

            typedef typename add_reference<second_type>::type type;

            BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED
            static type
            call(Iterator const& it)
            {
                return it.seq_.get(typename Iterator::index()).second;
            }
        };

        template <typename Iterator, typename N>
        struct advance
        {
            typedef typename Iterator::index index;
            typedef typename Iterator::sequence sequence;
            typedef map_iterator<sequence, index::value + N::value> type;

            BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED
            static type
            call(Iterator const& i)
            {
                return type(i.seq_);
            }
        };

        template<typename Iterator>
        struct next
            : advance<Iterator, mpl::int_<1> >
        {};

        template<typename Iterator>
        struct prior
            : advance<Iterator, mpl::int_<-1> >
        {};

        template <typename I1, typename I2>
        struct distance
        {
            typedef typename
                mpl::minus<
                    typename I2::index, typename I1::index
                >::type
            type;

            BOOST_CONSTEXPR BOOST_FUSION_GPU_ENABLED
            static type
            call(I1 const&, I2 const&)
            {
                return type();
            }
        };

        template<typename I1, typename I2>
        struct equal_to
            : mpl::equal_to<typename I1::index, typename I2::index>
        {};

        Seq& seq_;

    private:
        // silence MSVC warning C4512: assignment operator could not be generated
        map_iterator& operator= (map_iterator const&);
    };

}}

#ifdef BOOST_FUSION_WORKAROUND_FOR_LWG_2408
namespace std
{
    template <typename Seq, int Pos>
    struct iterator_traits< ::boost::fusion::map_iterator<Seq, Pos> >
    { };
}
#endif

#endif


code:
//---------------------------------------------------------------------------//
// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
//
// 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
//
// See http://boostorg.github.com/compute for more information.
//---------------------------------------------------------------------------//

#ifndef BOOST_COMPUTE_PLATFORM_HPP
#define BOOST_COMPUTE_PLATFORM_HPP

#include <algorithm>
#include <string>
#include <vector>

#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>

#include <boost/compute/cl.hpp>
#include <boost/compute/device.hpp>
#include <boost/compute/detail/get_object_info.hpp>

namespace boost {
namespace compute {

/// \class platform
/// \brief A compute platform.
///
/// The platform class provides an interface to an OpenCL platform.
///
/// To obtain a list of all platforms on the system use the
/// system::platforms() method.
///
/// \see device, context
class platform
{
public:
    /// Creates a new platform object for \p id.
    explicit platform(cl_platform_id id)
        : m_platform(id)
    {
    }

    /// Creates a new platform as a copy of \p other.
    platform(const platform &other)
        : m_platform(other.m_platform)
    {
    }

    /// Copies the platform id from \p other.
    platform& operator=(const platform &other)
    {
        if(this != &other){
            m_platform = other.m_platform;
        }

        return *this;
    }

    /// Destroys the platform object.
    ~platform()
    {
    }

    /// Returns the ID of the platform.
    cl_platform_id id() const
    {
        return m_platform;
    }

    /// Returns the name of the platform.
    std::string name() const
    {
        return get_info<std::string>(CL_PLATFORM_NAME);
    }

    /// Returns the name of the vendor for the platform.
    std::string vendor() const
    {
        return get_info<std::string>(CL_PLATFORM_VENDOR);
    }

    /// Returns the profile string for the platform.
    std::string profile() const
    {
        return get_info<std::string>(CL_PLATFORM_PROFILE);
    }

    /// Returns the version string for the platform.
    std::string version() const
    {
        return get_info<std::string>(CL_PLATFORM_VERSION);
    }

    /// Returns a list of extensions supported by the platform.
    std::vector<std::string> extensions() const
    {
        std::string extensions_string =
            get_info<std::string>(CL_PLATFORM_EXTENSIONS);
        std::vector<std::string> extensions_vector;
        boost::split(extensions_vector,
                     extensions_string,
                     boost::is_any_of("\t "),
                     boost::token_compress_on);
        return extensions_vector;
    }

    /// Returns \c true if the platform supports the extension with
    /// \p name.
    bool supports_extension(const std::string &name) const
    {
        const std::vector<std::string> extensions = this->extensions();

        return std::find(
            extensions.begin(), extensions.end(), name) != extensions.end();
    }

    /// Returns a list of devices on the platform.
    std::vector<device> devices(cl_device_type type = CL_DEVICE_TYPE_ALL) const
    {
        size_t count = device_count(type);
        if(count == 0){
            // no devices for this platform
            return std::vector<device>();
        }

        std::vector<cl_device_id> device_ids(count);
        cl_int ret = clGetDeviceIDs(m_platform,
                                    type,
                                    static_cast<cl_uint>(count),
                                    &device_ids[0],
                                    0);
        if(ret != CL_SUCCESS){
            BOOST_THROW_EXCEPTION(opencl_error(ret));
        }

        std::vector<device> devices;
        for(cl_uint i = 0; i < count; i++){
            devices.push_back(device(device_ids[i]));
        }

        return devices;
    }

    /// Returns the number of devices on the platform.
    size_t device_count(cl_device_type type = CL_DEVICE_TYPE_ALL) const
    {
        cl_uint count = 0;
        cl_int ret = clGetDeviceIDs(m_platform, type, 0, 0, &count);
        if(ret != CL_SUCCESS){
            if(ret == CL_DEVICE_NOT_FOUND){
                // no devices for this platform
                return 0;
            }
            else {
                // something else went wrong
                BOOST_THROW_EXCEPTION(opencl_error(ret));
            }
        }

        return count;
    }

    /// Returns information about the platform.
    ///
    /// \see_opencl_ref{clGetPlatformInfo}
    template<class T>
    T get_info(cl_platform_info info) const
    {
        return detail::get_object_info<T>(clGetPlatformInfo, m_platform, info);
    }

    /// \overload
    template<int Enum>
    typename detail::get_object_info_type<platform, Enum>::type
    get_info() const;

    /// Returns the address of the \p function_name extension
    /// function. Returns \c 0 if \p function_name is invalid.
    void* get_extension_function_address(const char *function_name) const
    {
        #ifdef CL_VERSION_1_2
        return clGetExtensionFunctionAddressForPlatform(m_platform,
                                                        function_name);
        #else
        return clGetExtensionFunctionAddress(function_name);
        #endif
    }

    /// Requests that the platform unload any compiler resources.
    void unload_compiler()
    {
        #ifdef CL_VERSION_1_2
        clUnloadPlatformCompiler(m_platform);
        #else
        clUnloadCompiler();
        #endif
    }

    /// Returns \c true if the platform is the same at \p other.
    bool operator==(const platform &other) const
    {
        return m_platform == other.m_platform;
    }

    /// Returns \c true if the platform is different from \p other.
    bool operator!=(const platform &other) const
    {
        return m_platform != other.m_platform;
    }

private:
    cl_platform_id m_platform;
};

/// \internal_ define get_info() specializations for platform
BOOST_COMPUTE_DETAIL_DEFINE_GET_INFO_SPECIALIZATIONS(platform,
    ((std::string, CL_PLATFORM_PROFILE))
    ((std::string, CL_PLATFORM_VERSION))
    ((std::string, CL_PLATFORM_NAME))
    ((std::string, CL_PLATFORM_VENDOR))
    ((std::string, CL_PLATFORM_EXTENSIONS))
)

inline boost::compute::platform device::platform() const
{
    return boost::compute::platform(get_info<CL_DEVICE_PLATFORM>());
}

} // end compute namespace
} // end boost namespace

#endif // BOOST_COMPUTE_PLATFORM_HPP


code:
// Copyright David Abrahams 2003.
// 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 COPY_CTOR_MUTATES_RHS_DWA2003219_HPP
# define COPY_CTOR_MUTATES_RHS_DWA2003219_HPP

#include <boost/python/detail/is_auto_ptr.hpp>
#include <boost/mpl/bool.hpp>

namespace boost { namespace python { namespace detail {

template <class T>
struct copy_ctor_mutates_rhs
    : is_auto_ptr<T>
{
};

}}} // namespace boost::python::detail

#endif // COPY_CTOR_MUTATES_RHS_DWA2003219_HPP


code:
_WSJT-X_ v1.9 suppports a number of features designed for use
on the VHF and higher bands.  These features include:

- *FT8*, a mode designed for making fast QSOs with weak, fading
signals

- *JT4*, a mode particularly useful for EME on the microwave bands

- *JT9* fast modes, useful for scatter propagation on VHF bands

- *JT65*, widely used for EME on VHF and higher bands

- *QRA64*, a mode for EME using a "`Q-ary Repeat Accumulate`" code,
a low-density parity-check (LDPC) code using a 64-character symbol
alphabet

- *MSK144*, a mode for meteor scatter using a binary LDPC code and
Offset Quadrature Phase-Shift Keying (OQPSK).  The resulting waveform
is sometimes called Minimum Shift Keying (MSK).

- *ISCAT*, intended for aircraft scatter and other types of scatter
propagation

- *Echo* mode, for detecting and measuring your own lunar echoes

- *Doppler tracking*, which becomes increasingly important for EME
on bands above 1.2 GHz.

- Optional *Auto-Sequencing* in JT4, JT9, and JT65 as well as FT8 and QRA64.

[[VHF_SETUP]]
=== VHF Setup

To activate the VHF-and-up features:

- On the *Settings | General* tab check *Enable VHF/UHF/Microwave
features* and *Single decode*.

- For EME, check *Decode after EME delay* to allow for extra path
delay on received signals.

- If you will use automatic Doppler tracking and your radio accepts
frequency-setting commands while transmitting, check *Allow Tx
frequency changes while transmitting*.  Transceivers known to permit
such changes include the IC-735, IC-756 Pro II, IC-910-H, FT-847,
TS-590S, TS-590SG, TS-2000 (with Rev 9 or later firmware upgrade),
Flex 1500 and 5000, HPSDR, Anan-10, Anan-100, and KX3.  To gain full
benefit of Doppler tracking your radio should allow frequency changes
under CAT control in 1 Hz steps.

NOTE: If your radio does not accept commands to change frequency
while transmitting, Doppler tracking will be approximated with a
single Tx frequency adjustment before a transmission starts, using a
value computed for the middle of the Tx period.

- On the *Radio* tab select *Split Operation* (use either *Rig* or
*Fake It*; you may need to experiment with both options to find one
that works best with your radio).

- On the right side of the main window select *Tab 1* to present the
traditional format for entering and choosing Tx messages.

The main window will reconfigure itself as necessary to display
controls supporting the features of each mode.

- If you are using transverters, set appropriate frequency offsets on
the *Settings | Frequencies* tab.  Offset is defined as (transceiver
dial reading) minus (on-the-air frequency).  For example, when using a
144 MHz radio at 10368 MHz, *Offset (MHz)* = (144 - 10368) =
-10224.000.  If the band is already in the table, you can edit the
offset by double clicking on the offset field itself.  Otherwise a new
band can be added by right clicking in the table and selecting
*Insert*.

image::Add_station_info.png[align="center",alt="Station information"]

- On the *View* menu, select *Astronomical data* to display a window
with important information for tracking the Moon and performing
automatic Doppler control.  The right-hand portion of the window
becomes visible when you check *Doppler tracking*.

image::Astronomical_data.png[align="center",alt="Astronomical data"]

Five different types of Doppler tracking are provided:

- Select *Full Doppler to DX Grid* if you know your QSO partner's locator
and he/she will not be using any Doppler control.

- Select *Own Echo* to enable EME Doppler tracking of your receive
frequency to your own echo frequency. Your Tx frequency will remain fixed
and is set to the Sked frequency.  This mode can be used when announcing
your CQ call on a specific frequency and listening on your own echo
frequency.  It can also be used for echo testing with Echo mode.

- Select *Constant frequency on Moon* to correct for your own one-way
Doppler shift to or from the Moon.  If your QSO partner does the same
thing, both stations will have the required Doppler compensation.
Moreover, anyone else using this option will hear both of you
without the need for manual frequency changes.

- Select *On Dx Echo* when your QSO partner is not using automated
Doppler tracking, and announces his/her transmit frequency and listening
on their own echo frequency. When clicked, this Doppler method will
set your rig frequency on receive to correct for the mutual Doppler
shift.  On transmit, your rig frequency will be set so that your
QSO partner will receive you on the same frequency as their own echo
at the start of the QSO. As the QSO proceeds, your QSO partner will
receive you on this starting frequency so that they do not have to
retune their receiver as the Doppler changes.  Sked frequency in this
case is set to that announced by your QSO partner.

- Select *Call DX* after tuning the radio manually to find a station,
with the Doppler mode initally set to *None*. You may be tuning the band
looking for random stations, or to a frequency where a station has been
seen on an SDR display.  It is usually necessary to hold down the Ctrl key
while tuning the radio. From the moment *Call DX* is pressed, your
transmit frequency is set so that your echo will fall on the same
frequency you (and the DX station) are listening.

- See <<ASTRODATA,Astronomical Data>> for details on the quantities
displayed in this window.

=== JT4

JT4 is designed especially for EME on the microwave bands, 2.3 GHz and
above.

- Select *JT4* from the *Mode* menu.  The central part of the main
window will look something like this:

image::VHF_controls.png[align="center",alt="VHF Controls"]

- Select the desired *Submode*, which determines the spacing of
transmitted tones. Wider spacings are used on the higher microwave
bands to allow for larger Doppler spreads. For example, submode JT4F
is generally used for EME on the 5.7 and 10 GHz bands.

- For EME QSOs some operators use short-form JT4 messages consisting
of a single tone.  To activate automatic generation of these messages,
check the box labeled *Sh*. This also enables the generation of a
single tone at 1000Hz by selecting Tx6, to assist in finding signals
initially.  The box labeled *Tx6* toggles the Tx6 message from 1000Hz
to 1250Hz to indicate to the other station that you are ready to
receive messages.

- Select *Deep* from the *Decode* menu.  You may also choose to
*Enable averaging* over successive transmissions and/or *Enable deep
search* (correlation decoding).

image::decode-menu.png[align="center",alt="Decode Menu"]

The following screen shot shows one transmission from a 10 GHz EME
QSO using submode JT4F.

image::JT4F.png[align="center",alt="JT4F"]

=== JT65

In many ways JT65 operation on VHF and higher bands is similar to HF
usage, but a few important differences should be noted.  Typical
VHF/UHF operation involves only a single signal (or perhaps two or
three) in the receiver passband.  You may find it best to check
*Single decode* on the *Settings -> General* tab.  There will be
little need for *Two pass decoding* on the *Advanced* tab.  With VHF
features enabled the JT65 decoder will respond to special message
formats often used for EME: the OOO signal report and two-tone
shorthand messages for RO, RRR, and 73.  These messages are always
enabled for reception; they will be automatically generated for
transmission if you check the shorthand message box *Sh*.

*Deep* on the *Decode* menu will be automatically selected.  You may
optionally include *Enable averaging*, *Enable Deep search*, and
*Enable AP*.

The following screen shot shows three transmissions from a 144 MHz EME
QSO using submode JT65B and shorthand messages.  Take note of the
colored tick marks on the Wide Graph frequency scale.  The green
marker at 1220 Hz indicates the selected QSO frequency (the frequency
of the JT65 Sync tone) and the *F Tol* range.  A green tick at 1575 Hz
marks the frequency of the highest JT65 data tone.  Orange markers
indicate the frequency of the upper tone of the two-tone signals for
RO, RRR, and 73.

image::JT65B.png[align="center",alt="JT65B"]

=== QRA64

QRA64 is designed for EME on VHF and higher bands; its
operation is generally similar to JT4 and JT65.  The following screen
shot shows an example of a QRA64C transmission from DL7YC recorded at
G3WDG over the EME path at 24 GHz.  Doppler spread on the path was 78
Hz, so although the signal is reasonably strong its tones are
broadened enough to make them hard to see on the waterfall.  The
triangular red marker below the frequency scale shows that the decoder
has achieved synchronization with a signal at approximately 967 Hz.

image::QRA64.png[align="center",alt="QRA64"]

The QRA64 decoder makes no use of a callsign database.  Instead, it
takes advantage of _a priori_ (AP) information such as one's own
callsign and the encoded form of message word `CQ`.  In normal usage,
as a QSO progresses the available AP information increases to include
the callsign of the station being worked and perhaps also his/her
4-digit grid locator.  The decoder always begins by attempting to
decode the full message using no AP information.  If this attempt
fails, additional attempts are made using available AP information to
provide initial hypotheses about the message content.  At the end of
each iteration the decoder computes the extrinsic probability of the
most likely value for each of the message's 12 six-bit information
symbols.  A decode is declared only when the total probability for all
12 symbols has converged to an unambiguous value very close to 1.

For EME QSOs some operators use short-form QRA64 messages consisting
of a single tone.  To activate automatic generation of these messages,
check the box labeled *Sh*.  This also enables the generation of a
single tone at 1000Hz by selecting Tx6, to assist in finding  signals
initially, as the QRA64 tones are often not visible on the waterfall.
The box labeled *Tx6* switches the Tx6 message from 1000Hz to 1250Hz
to indicate to the other station that you are ready to receive messages.

TIP: QRA64 is different from JT65 in that the decoder attempts to find
and decode only a single signal in the receiver passband.  If many
signals are present you may be able to decode them by double-clicking
on the lowest tone of each one in the waterfall.

TIP: G3WDG has prepared a more detailed tutorial on using {QRA64_EME}.

=== ISCAT

ISCAT is a useful mode for signals that are weak but more or less
steady in amplitude over several seconds or longer.  Aircraft scatter
at 10 GHz is a good example.  ISCAT messages are free-format and may
have any length from 1 to 28 characters.  This protocol includes no
error-correction facility.

=== MSK144

Meteor-scatter QSOs can be made any time on the VHF bands at distances
up to about 2100 km (1300 miles).  Completing a QSO takes longer in
the evening than in the morning, longer at higher frequencies, and
longer at distances close to the upper limit.  But with patience, 100
Watts or more, and a single yagi it can usually be done.  The
following screen shot shows two 15-second MSK144 transmissions from
W5ADD during a 50 MHz QSO with K1JT, at a distance of about 1800 km
(1100 mi).  The decoded segments have been marked on the *Fast
Graph* spectral display.

image::MSK144.png[align="center",alt="MSK144"]

Unlike other _WSJT-X_ modes, the MSK144 decoder operates in real time
during the reception sequence.  Decoded messages will appear on your
screen almost as soon as you hear them.

To configure _WSJT-X_ for MSK144 operation:

- Select *MSK144* from the *Mode* menu.

- Select *Fast* from the *Decode* menu.

- Set the audio receiving frequency to *Rx 1500 Hz*.

- Set frequency tolerance to *F Tol 100*.

- Set the *T/R* sequence duration to 15 s.

- To match decoding depth to your computer's capability, click
*Monitor* (if it's not already green) to start a receiving sequence.
Observe the percentage figure displayed on the _Receiving_ label in
the Status Bar:

image::Rx_pct_MSK144.png[align="center",alt="MSK144 Percent CPU"]

- The displayed number (here 17%) indicates the fraction of available
time being used for execution of the MSK144 real-time decoder.  If
this number is well below 100% you may increase the decoding depth
from *Fast* to *Normal* or *Deep*, and increase *F Tol* from 100 to
200 Hz.

NOTE: Most modern multi-core computers can easily handle the optimum
parameters *Deep* and *F Tol 200*.  Older and slower machines may not
be able to keep up at these settings; at the *Fast* and *Normal*
settings there will be a small loss in decoding capability (relative
to *Deep*) for the weakest pings.

- T/R sequences of 15 seconds or less requires selecting your
transmitted messages very quickly.  Check *Auto Seq* to have the
computer make the necessary decisions automatically, based on the
messages received.

- For operation at 144 MHz or above you may find it helpful to use
short-format *Sh* messages for Tx3, Tx4, and Tx5.  These messages are
20 ms long, compared with 72 ms for full-length MSK144 messages.
Their information content is a 12-bit hash of the two callsigns,
rather than the callsigns themselves, plus a 4-bit numerical report,
acknowledgment (RRR), or sign-off (73).  Only the intended recipient
can decode short-messages.  They will be displayed with the callsigns
enclosed in <> angle brackets, as in the following model QSO

 CQ K1ABC FN42
                    K1ABC W9XYZ EN37
 W9XYZ K1ABC +02
                    <K1ABC W9XYZ> R+03
 <W9XYZ K1ABC> RRR
                    <K1ABC W9XYZ> 73

NOTE: There is little or no advantage to using MSK144 *Sh*
messages at 50 or 70 MHz.  At these frequencies, most pings are long
enough to support standard messages -- which have the advantage of
being readable by anyone listening in.

=== Echo Mode

*Echo* mode allows you to make sensitive measurements of your own
lunar echoes even when they are too weak to be heard. Select *Echo*
from the *Mode* menu, aim your antenna at the moon, pick a clear
frequency, and toggle click *Tx Enable*. _WSJT-X_ will then cycle
through the following loop every 6 seconds:

1. Transmit a 1500 Hz fixed tone for 2.3 s
2. Wait about 0.2 s for start of the return echo
3. Record the received signal for 2.3 s
4. Analyze, average, and display the results
5. Repeat from step 1

To make a sequence of echo tests:

- Select *Echo* from the *Mode* menu.

- Check *Doppler tracking* and *Constant frequency on the Moon* on the
Astronomical Data window.

- Be sure that your rig control has been set up for _Split Operation_,
using either *Rig* or *Fake It* on the *Settings | Radio* tab.

- Click *Enable Tx* on the main window to start a sequence of 6-second
cycles.

- _WSJT-X_ calculates and compensates for Doppler shift automatically.
As shown in the screen shot below, when proper Doppler corrections
have been applied your return echo should always appear at the center
of the plot area on the Echo Graph window.

image::echo_144.png[align="center",alt="Echo 144 MHz"]

=== VHF+ Sample Files

Sample recordings typical of QSOs using the VHF/UHF/Microwave modes
and features of _WSJT-X_ are available for
<<DOWNLOAD_SAMPLES,download>>.  New users of the VHF-and-up features
are strongly encouraged to practice decoding the signals in these
files.


code:
/*
Copyright Rene Rivera 2008-2015
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_PREDEF_LIBRARY_C_UC_H
#define BOOST_PREDEF_LIBRARY_C_UC_H

#include <boost/predef/library/c/_prefix.h>

#include <boost/predef/version_number.h>
#include <boost/predef/make.h>

/*`
[heading `BOOST_LIB_C_UC`]

[@http://en.wikipedia.org/wiki/Uclibc uClibc] Standard C library.

[table
    [[__predef_symbol__] [__predef_version__]]

    [[`__UCLIBC__`] [__predef_detection__]]

    [[`__UCLIBC_MAJOR__`, `__UCLIBC_MINOR__`, `__UCLIBC_SUBLEVEL__`] [V.R.P]]
    ]
 */

#define BOOST_LIB_C_UC BOOST_VERSION_NUMBER_NOT_AVAILABLE

#if defined(__UCLIBC__)
#   undef BOOST_LIB_C_UC
#   define BOOST_LIB_C_UC BOOST_VERSION_NUMBER(\
        __UCLIBC_MAJOR__,__UCLIBC_MINOR__,__UCLIBC_SUBLEVEL__)
#endif

#if BOOST_LIB_C_UC
#   define BOOST_LIB_C_UC_AVAILABLE
#endif

#define BOOST_LIB_C_UC_NAME "uClibc"

#endif

#include <boost/predef/detail/test.h>
BOOST_PREDEF_DECLARE_TEST(BOOST_LIB_C_UC,BOOST_LIB_C_UC_NAME)


code:
/*==============================================================================
    Copyright (c) 2005-2010 Joel de Guzman
    Copyright (c) 2010 Thomas Heller

    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_PHOENIX_DEFINE_OPERATOR_HPP
#define BOOST_PHOENIX_DEFINE_OPERATOR_HPP

#include <boost/phoenix/core/meta_grammar.hpp>
#include <boost/preprocessor/seq/for_each.hpp>

#define BOOST_PHOENIX_UNARY_EXPRESSION(__, ___, name)                           \
    template <typename Operand>                                                 \
    struct name                                                                 \
        : expr<proto::tag::name, Operand>                                       \
    {};                                                                         \
/**/

#define BOOST_PHOENIX_UNARY_RULE(__, ___, name)                                 \
    struct name                                                                 \
        : expression::name<meta_grammar>                                        \
    {};                                                                         \
/**/

#define BOOST_PHOENIX_UNARY_FUNCTIONAL(__, ___, name)                           \
    namespace functional                                                        \
    {                                                                           \
        typedef                                                                 \
            proto::functional::make_expr<proto::tag::name>                      \
            BOOST_PP_CAT(make_, name);                                          \
    }                                                                           \
    namespace result_of                                                         \
    {                                                                           \
        template <typename Operand>                                             \
        struct BOOST_PP_CAT(make_, name)                                        \
            : boost::result_of<                                                 \
                functional:: BOOST_PP_CAT(make_, name)(                         \
                    Operand                                                     \
                )                                                               \
            >                                                                   \
        {};                                                                     \
    }                                                                           \
    template <typename Operand>                                                 \
    inline                                                                      \
    typename result_of::BOOST_PP_CAT(make_, name)<Operand>::type                \
    BOOST_PP_CAT(make_, name)(Operand const & operand)                          \
    {                                                                           \
        return functional::BOOST_PP_CAT(make_, name)()(operand);                \
    }                                                                           \
/**/

#define BOOST_PHOENIX_BINARY_EXPRESSION(__, ___, name)                          \
    template <typename Lhs, typename Rhs>                                       \
    struct name                                                                 \
        : expr<proto::tag::name, Lhs, Rhs>                                      \
    {};                                                                         \
/**/

#define BOOST_PHOENIX_BINARY_RULE(__, ___, name)                                \
    struct name                                                                 \
        : expression::name<meta_grammar, meta_grammar>                          \
    {};                                                                         \
/**/

#define BOOST_PHOENIX_BINARY_FUNCTIONAL(__, ___, name)                          \
    namespace functional                                                        \
    {                                                                           \
        typedef                                                                 \
            proto::functional::make_expr<proto::tag::name>                      \
            BOOST_PP_CAT(make_, name);                                          \
    }                                                                           \
    namespace result_of                                                         \
    {                                                                           \
        template <typename Lhs, typename Rhs>                                   \
        struct BOOST_PP_CAT(make_, name)                                        \
            : boost::result_of<                                                 \
                functional:: BOOST_PP_CAT(make_, name)(                         \
                    Lhs, Rhs                                                    \
                )                                                               \
            >                                                                   \
        {};                                                                     \
    }                                                                           \
    template <typename Rhs, typename Lhs>                                       \
    inline                                                                      \
    typename result_of::BOOST_PP_CAT(make_, name)<Rhs, Lhs>::type               \
    BOOST_PP_CAT(make_, name)(Lhs const & lhs, Rhs const & rhs)                 \
    {                                                                           \
        return functional::BOOST_PP_CAT(make_, name)()(lhs, rhs);               \
    }                                                                           \
/**/

#define BOOST_PHOENIX_GRAMMAR(_, __, name)                                      \
    template <typename Dummy>                                                   \
    struct meta_grammar::case_<proto::tag::name, Dummy>                         \
        : enable_rule<rule::name, Dummy>                                        \
    {};                                                                         \
/**/

#define BOOST_PHOENIX_UNARY_OPERATORS(ops)                                      \
    namespace expression {                                                      \
        BOOST_PP_SEQ_FOR_EACH(BOOST_PHOENIX_UNARY_EXPRESSION, _, ops)           \
    }                                                                           \
    namespace rule {                                                            \
        BOOST_PP_SEQ_FOR_EACH(BOOST_PHOENIX_UNARY_RULE, _, ops)                 \
    }                                                                           \
    BOOST_PP_SEQ_FOR_EACH(BOOST_PHOENIX_GRAMMAR, _, ops)                        \
    BOOST_PP_SEQ_FOR_EACH(BOOST_PHOENIX_UNARY_FUNCTIONAL, _, ops)               \
/**/

#define BOOST_PHOENIX_BINARY_OPERATORS(ops)                                     \
    namespace expression {                                                      \
        BOOST_PP_SEQ_FOR_EACH(BOOST_PHOENIX_BINARY_EXPRESSION, _, ops)          \
    }                                                                           \
    namespace rule {                                                            \
        BOOST_PP_SEQ_FOR_EACH(BOOST_PHOENIX_BINARY_RULE, _, ops)                \
    }                                                                           \
    BOOST_PP_SEQ_FOR_EACH(BOOST_PHOENIX_GRAMMAR, _, ops)                        \
    BOOST_PP_SEQ_FOR_EACH(BOOST_PHOENIX_BINARY_FUNCTIONAL, _, ops)              \
/**/

#endif


code:
#ifndef BOOST_ATOMIC_HPP
#define BOOST_ATOMIC_HPP

//  Copyright (c) 2011 Helge Bahmann
//
//  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)

// This header includes all Boost.Atomic public headers

#include <boost/atomic/atomic.hpp>

#ifdef BOOST_HAS_PRAGMA_ONCE
#pragma once
#endif

#endif


code:
// Boost.Units - A C++ library for zero-overhead dimensional analysis and
// unit/quantity manipulation and conversion
//
// Copyright (C) 2003-2008 Matthias Christian Schabel
// Copyright (C) 2008 Steven Watanabe
//
// 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_UNITS_SI_MOMENTUM_HPP
#define BOOST_UNITS_SI_MOMENTUM_HPP

#include <boost/units/systems/si/base.hpp>
#include <boost/units/physical_dimensions/momentum.hpp>

namespace boost {

namespace units {

namespace si {

typedef unit<momentum_dimension,si::system>  momentum;

} // namespace si

} // namespace units

} // namespace boost

#endif // BOOST_UNITS_SI_MOMENTUM_HPP


code:
/*==============================================================================
    Copyright (c) 2001-2010 Joel de Guzman
    Copyright (c) 2010 Thomas Heller

    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_PHOENIX_STATEMENT_SWITCH_HPP
#define BOOST_PHOENIX_STATEMENT_SWITCH_HPP

#include <boost/phoenix/core/limits.hpp>
#include <boost/fusion/iterator/advance.hpp>
#include <boost/phoenix/core/call.hpp>
#include <boost/phoenix/core/expression.hpp>
#include <boost/phoenix/core/meta_grammar.hpp>
#include <boost/phoenix/core/is_nullary.hpp>
#include <boost/phoenix/support/iterate.hpp>
#include <boost/proto/make_expr.hpp>
#include <boost/proto/fusion.hpp>

#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4065) // switch statement contains 'default' but no 'case' labels
#endif

BOOST_PHOENIX_DEFINE_EXPRESSION(
    (boost)(phoenix)(switch_case)
  , (proto::terminal<proto::_>)
    (meta_grammar)
)

BOOST_PHOENIX_DEFINE_EXPRESSION(
    (boost)(phoenix)(switch_default_case)
  , (meta_grammar)
)

namespace boost { namespace phoenix
{
    namespace detail
    {
        struct switch_case_grammar;
        struct switch_case_with_default_grammar;
        struct switch_grammar
            : proto::or_<
                proto::when<
                    detail::switch_case_grammar
                  , mpl::false_()
                >
              , proto::when<
                    detail::switch_case_with_default_grammar
                  , mpl::true_()
                >
            >
        {};
    }

    namespace detail
    {
        struct switch_case_is_nullary
            : proto::or_<
                proto::when<
                    proto::comma<
                        switch_case_is_nullary
                      , proto::or_<phoenix::rule::switch_default_case, phoenix::rule::switch_case>
                    >
                  , mpl::and_<
                        switch_case_is_nullary(
                            proto::_child_c<0>
                          , proto::_state
                        )
                      , switch_case_is_nullary(
                            proto::_child_c<1>
                          , proto::_state
                        )
                    >()
                >
              , proto::when<
                    proto::or_<phoenix::rule::switch_default_case, phoenix::rule::switch_case>
                  , evaluator(proto::_child_c<0>, proto::_state)
                >
            >
        {};

        struct switch_case_grammar
            : proto::or_<
                proto::comma<switch_case_grammar, phoenix::rule::switch_case>
              , proto::when<phoenix::rule::switch_case, proto::_>
            >
        {};

        struct switch_case_with_default_grammar
            : proto::or_<
                proto::comma<switch_case_grammar, phoenix::rule::switch_default_case>
              , proto::when<phoenix::rule::switch_default_case, proto::_>
            >
        {};

        struct switch_size
            : proto::or_<
                proto::when<
                    proto::comma<switch_size, proto::_>
                  , mpl::next<switch_size(proto::_left)>()
                >
              , proto::when<proto::_, mpl::int_<1>()>
            >
        {};
    }
}}

BOOST_PHOENIX_DEFINE_EXPRESSION(
    (boost)(phoenix)(switch_)
  , (meta_grammar)           // Cond
    (detail::switch_grammar) // Cases
)

namespace boost { namespace phoenix {

    template <typename Dummy>
    struct is_nullary::when<rule::switch_, Dummy>
        : proto::and_<
            evaluator(proto::_child_c<0>, _context)
          , detail::switch_case_is_nullary(proto::_child_c<1>, _context)
        >
    {};

    struct switch_eval
    {
        typedef void result_type;

        template <typename Context>
        result_type
        operator()(Context const &) const
        {
        }

        template <typename Cond, typename Cases, typename Context>
        result_type
        operator()(Cond const & cond, Cases const & cases, Context const & ctx) const
        {
            this->evaluate(
                    ctx
                  , cond
                  , cases
                  , typename detail::switch_size::impl<Cases, int, proto::empty_env>::result_type()
                  , typename detail::switch_grammar::impl<Cases, int, proto::empty_env>::result_type()
                );
        }

        private:
            template <typename Context, typename Cond, typename Cases>
            result_type
            evaluate(
                Context const & ctx
              , Cond const & cond
              , Cases const & cases
              , mpl::int_<1>
              , mpl::false_
            ) const
            {
                typedef
                    typename proto::result_of::value<
                        typename proto::result_of::child_c<
                            Cases
                          , 0
                        >::type
                    >::type
                    case_label;

                switch(boost::phoenix::eval(cond, ctx))
                {
                    case case_label::value:
                        boost::phoenix::eval(proto::child_c<1>(cases), ctx);
                }
            }

            template <typename Context, typename Cond, typename Cases>
            result_type
            evaluate(
                Context const & ctx
              , Cond const & cond
              , Cases const & cases
              , mpl::int_<1>
              , mpl::true_
            ) const
            {
                switch(boost::phoenix::eval(cond, ctx))
                {
                    default:
                        boost::phoenix::eval(proto::child_c<0>(cases), ctx);
                }
            }

            // Bring in the evaluation functions
            #include <boost/phoenix/statement/detail/switch.hpp>
    };

    template <typename Dummy>
    struct default_actions::when<rule::switch_, Dummy>
        : call<switch_eval>
    {};

    template <int N, typename A>
    inline
    typename proto::result_of::make_expr<
        tag::switch_case
      , proto::basic_default_domain
      , mpl::int_<N>
      , A
    >::type const
    case_(A const & a)
    {
        return
            proto::make_expr<
                tag::switch_case
              , proto::basic_default_domain
            >(
                mpl::int_<N>()
              , a
            );
    }

    template <typename A>
    inline
    typename proto::result_of::make_expr<
        tag::switch_default_case
      , proto::basic_default_domain
      , A
    >::type const
    default_(A const& a)
    {
        return
            proto::make_expr<
                tag::switch_default_case
              , proto::basic_default_domain
            >(a);
    }

    template <typename Cond>
    struct switch_gen
    {
        switch_gen(Cond const& cond_) : cond(cond_) {}

        template <typename Cases>
        typename expression::switch_<
            Cond
          , Cases
        >::type
        operator[](Cases const& cases) const
        {
            return
                this->generate(
                    cases
                  , proto::matches<Cases, detail::switch_grammar>()
                );
        }

        private:
            Cond const& cond;

            template <typename Cases>
            typename expression::switch_<
                Cond
              , Cases
            >::type
            generate(Cases const & cases, mpl::true_) const
            {
                return expression::switch_<Cond, Cases>::make(cond, cases);
            }

            template <typename Cases>
            typename expression::switch_<
                Cond
              , Cases
            >::type
            generate(Cases const &, mpl::false_) const
            {
                BOOST_MPL_ASSERT_MSG(
                    false
                  , INVALID_SWITCH_CASE_STATEMENT
                  , (Cases)
                );
            }
    };

    template <typename Cond>
    inline
    switch_gen<Cond> const
    switch_(Cond const& cond)
    {
        return switch_gen<Cond>(cond);
    }

}}

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#endif