text: /*=============================================================================
      Copyright (c) 2004 Angus Leeming
      Copyright (c) 2004 Joel de Guzman
  
      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_STL_CONTAINER_CONTAINER_HPP
  #define BOOST_PHOENIX_STL_CONTAINER_CONTAINER_HPP
  
  #include <boost/phoenix/core/limits.hpp>
  #include <boost/mpl/and.hpp>
  #include <boost/mpl/not.hpp>
  #include <boost/mpl/or.hpp>
  #include <boost/mpl/void.hpp>
  #include <boost/phoenix/stl/container/detail/container.hpp>
  #include <boost/phoenix/function/adapt_callable.hpp>
  #include <boost/type_traits/is_const.hpp>
  
  namespace boost { namespace phoenix
  {
  ///////////////////////////////////////////////////////////////////////////////
  //
  //  STL container member functions
  //
  //      Lazy functions for STL container member functions
  //
  //      These functions provide a mechanism for the lazy evaluation of the
  //      public member functions of the STL containers. For an overview of
  //      what is meant by 'lazy evaluation', see the comments in operators.hpp
  //      and functions.hpp.
  //
  //      Lazy functions are provided for all of the member functions of the
  //      following containers:
  //
  //      deque - list - map - multimap - vector - set - multiset.
  //
  //      Indeed, should *your* class have member functions with the same names
  //      and signatures as those listed below, then it will automatically be
  //      supported. To summarize, lazy functions are provided for member
  //      functions:
  //
  //          assign - at - back - begin - capacity - clear - empty - end -
  //          erase - front - get_allocator - insert - key_comp - max_size -
  //          pop_back - pop_front - push_back - push_front - rbegin - rend -
  //          reserve - resize . size - splice - value_comp.
  //
  //      The lazy functions' names are the same as the corresponding member
  //      function. Sample usage:
  //
  //      "Normal" version                 "Lazy" version
  //      ----------------                 --------------
  //      my_vector.at(5)                  phoenix::at(arg1, 5)
  //      my_list.size()                   phoenix::size(arg1)
  //      my_vector1.swap(my_vector2)      phoenix::swap(arg1, arg2)
  //
  //      Notice that member functions with names that clash with a
  //      function in stl algorithms are absent. This will be provided
  //      in Phoenix's algorithm module.
  //
  //      No support is provided here for lazy versions of operator+=,
  //      operator[] etc. Such operators are not specific to STL containers and
  //      lazy versions can therefore be found in operators.hpp.
  //
  ///////////////////////////////////////////////////////////////////////////////
  
  ///////////////////////////////////////////////////////////////////////////////
  //
  //  Lazy member function implementaions.
  //
  //      The structs below provide the guts of the implementation. Thereafter,
  //      the corresponding lazy function itself is simply:
  //
  //          function<stl::assign> const assign = stl::assign();
  //
  //      The structs provide a nested "result" class template whose
  //      "type" typedef enables the lazy function to ascertain the type
  //      to be returned when it is invoked.
  //
  //      They also provide operator() member functions with signatures
  //      corresponding to those of the underlying member function of
  //      the STL container.
  //
  ///////////////////////////////////////////////////////////////////////////////
      namespace stl
      {
          struct assign
          {
              template <typename Sig>
              struct result;
  
              template <
                  typename This
                , typename C
                , typename Arg1
              >
              struct result<This(C&, Arg1&)>
              {
                  typedef typename add_reference<C>::type type;
              };
  
              template <
                  typename This
                , typename C
                , typename Arg1
                , typename Arg2
              >
              struct result<This(C&, Arg1, Arg2)>
              {
                  typedef typename add_reference<C>::type type;
              };
  
              template <
                  typename This
                , typename C
                , typename Arg1
                , typename Arg2
                , typename Arg3
              >
              struct result<This(C&, Arg1, Arg2, Arg3)>
              {
                  typedef typename add_reference<C>::type type;
              };
  
              template <typename C, typename Arg1>
              C& operator()(C& c, Arg1 const & arg1) const
              {
                  c.assign(arg1);
                  return c;
              }
  
              template <typename C, typename Arg1, typename Arg2>
              C& operator()(C& c, Arg1 arg1, Arg2 arg2) const
              {
                  c.assign(arg1, arg2);
                  return c;
              }
  
              template <typename C, typename Arg1, typename Arg2, typename Arg3>
              C& operator()(
                  C& c
                , Arg1 arg1
                , Arg2 arg2
                , Arg3 const & arg3
              ) const
              {
                  return c.assign(arg1, arg2, arg3);
              }
          };
  
          struct at_impl
          {
              template <typename Sig>
              struct result;
  
              template <typename This, typename C, typename Index>
              struct result<This(C&, Index)>
              {
                  //typedef typename const_qualified_reference_of<C>::type type;
                  typedef typename C::value_type & type;
              };
  
              template <typename C, typename Index>
              typename result<at_impl(C&, Index const&)>::type
              operator()(C& c, Index const &i) const
              {
                  return c.at(i);
              }
  
              template <typename This, typename C, typename Index>
              struct result<This(C const&, Index)>
              {
                  typedef typename C::value_type const & type;
              };
  
              template <typename C, typename Index>
              typename result<at_impl(C const&, Index const&)>::type
              operator()(C const& c, Index const &i) const
              {
                  return c.at(i);
              }
          };
  
          struct back
          {
              template <typename Sig>
              struct result;
  
              template <typename This, typename C>
              struct result<This(C&)>
              {
                  typedef
                      typename const_qualified_reference_of<C>::type
                  type;
              };
  
              template <typename C>
              typename result<back(C&)>::type
              operator()(C& c) const
              {
                  return c.back();
              }
          };
  
          struct begin
          {
              template <typename Sig>
              struct result;
  
              template <typename This, typename C>
              struct result<This(C&)>
              {
                  typedef typename const_qualified_iterator_of<C>::type type;
              };
  
              template <typename C>
              typename result<begin(C&)>::type
              operator()(C& c) const
              {
                  return c.begin();
              }
          };
  
          struct capacity
          {
              template <typename Sig>
              struct result;
  
              template <typename This, typename C>
              struct result<This(C&)>
              {
                  typedef typename size_type_of<C>::type type;
              };
  
              template <typename C>
              typename result<capacity(C&)>::type
              operator()(C const& c) const
              {
                  return c.capacity();
              }
          };
  
          struct clear
          {
              typedef void result_type;
  
              template <typename C>
              void operator()(C& c) const
              {
                  return c.clear();
              }
          };
  
          struct empty
          {
              typedef bool result_type;
  
              template <typename C>
              bool operator()(C const& c) const
              {
                  return c.empty();
              }
          };
  
          struct end
          {
              template <typename Sig>
              struct result;
  
              template <typename This, typename C>
              struct result<This(C&)>
              {
                  typedef typename const_qualified_iterator_of<C>::type type;
              };
  
              template <typename C>
              typename result<end(C&)>::type
              operator()(C& c) const
              {
                  return c.end();
              }
          };
  
          namespace result_of
          {
              template <typename C, typename Arg1, typename Arg2 = mpl::void_>
              struct erase
              {
                  // MSVC and libc++ always returns iterator even in C++03 mode.
                  typedef
                      boost::mpl::eval_if<
                          is_key_type_of<C, Arg1>
                        , size_type_of<C>
  #if defined(BOOST_MSVC) /*&& (BOOST_MSVC <= 1500)*/ \
   && (defined(BOOST_LIBSTDCXX11) && 40500 <= BOOST_LIBSTDCXX_VERSION) \
   && defined(_LIBCPP_VERSION)
                        , iterator_of<C>
  #else
                        , boost::mpl::identity<void>
  #endif
                      >
                  assoc_erase_result;
  
                  typedef typename
                      boost::mpl::eval_if_c<
                          has_key_type<C>::value
                        , assoc_erase_result
                        , iterator_of<C>
                      >::type
                  type;
              };
          }
  
          struct erase
          {
              //  This mouthful can differentiate between the generic erase
              //  functions (Container == std::deque, std::list, std::vector) and
              //  that specific to Associative Containers.
              //
              //  where C is a std::deque, std::list, std::vector:
              //
              //      1) iterator C::erase(iterator where);
              //      2) iterator C::erase(iterator first, iterator last);
              //
              //  where C is a std::map, std::multimap, std::set, or std::multiset:
              //
              //      3) size_type M::erase(const Key& keyval);
              //      4-a) void M::erase(iterator where);
              //      4-b) iterator M::erase(iterator where);
              //      5-a) void M::erase(iterator first, iterator last);
              //      5-b) iterator M::erase(iterator first, iterator last);
  
              template <typename Sig>
              struct result;
  
              template <typename This, typename C, typename Arg1>
              struct result<This(C&, Arg1)>
                  : result_of::erase<C, Arg1>
              {};
  
              template <typename This, typename C, typename Arg1, typename Arg2>
              struct result<This(C&, Arg1, Arg2)>
                  : result_of::erase<C, Arg1, Arg2>
              {};
  
              template <typename C, typename Arg1>
              typename result_of::erase<C, Arg1>::type
              operator()(C& c, Arg1 arg1) const
              {
                  typedef typename result_of::erase<C, Arg1>::type result_type;
                  return static_cast<result_type>(c.erase(arg1));
              }
  
              template <typename C, typename Arg1, typename Arg2>
              typename result_of::erase<C, Arg1, Arg2>::type
              operator()(C& c, Arg1 arg1, Arg2 arg2) const
              {
                  typedef typename result_of::erase<C, Arg1, Arg2>::type result_type;
                  return static_cast<result_type>(c.erase(arg1, arg2));
              }
          };
  
          struct front
          {
              template <typename Sig>
              struct result;
  
              template <typename This, typename C>
              struct result<This(C&)>
              {
                  typedef typename const_qualified_reference_of<C>::type type;
              };
  
              template <typename C>
              typename result<front(C&)>::type
              operator()(C& c) const
              {
                  return c.front();
              }
          };
  
          struct get_allocator
          {
              template <typename Sig>
              struct result;
  
              template <typename This, typename C>
              struct result<This(C&)>
              {
                  typedef typename allocator_type_of<C>::type type;
              };
  
              template <typename C>
              typename result<get_allocator(C const&)>::type
              operator()(C& c) const
              {
                  return c.get_allocator();
              }
          };
  
          namespace result_of
          {
              template <
                  typename C
                , typename Arg1
                , typename Arg2 = mpl::void_
                , typename Arg3 = mpl::void_
              >
              class insert
              {
                  struct pair_iterator_bool
                  {
                      typedef typename std::pair<typename C::iterator, bool> type;
                  };
  
                  typedef
                      boost::mpl::eval_if<
                          map_insert_returns_pair<typename remove_const<C>::type>
                        , pair_iterator_bool
                        , iterator_of<C>
                      >
                  choice_1;
  
                  typedef
                      boost::mpl::eval_if_c<
                          boost::mpl::and_<
                              boost::is_same<Arg3, mpl::void_>
                            , boost::mpl::not_<boost::is_same<Arg1, Arg2> >
                          >::value
                        , iterator_of<C>
                        , boost::mpl::identity<void>
                      >
                  choice_2;
  
              public:
  
                  typedef typename
                      boost::mpl::eval_if_c<
                          boost::is_same<Arg2, mpl::void_>::value
                        , choice_1
                        , choice_2
                      >::type
                  type;
              };
          }
  
          struct insert
          {
              //  This mouthful can differentiate between the generic insert
              //  functions (Container == deque, list, vector) and those
              //  specific to the two map-types, std::map and std::multimap.
              //
              //  where C is a std::deque, std::list, std::vector:
              //
              //      1) iterator C::insert(iterator where, value_type value);
              //      2) void C::insert(
              //          iterator where, size_type count, value_type value);
              //      3) template <typename Iter>
              //         void C::insert(iterator where, Iter first, Iter last);
              //
              //  where M is a std::map and MM is a std::multimap:
              //
              //      4) pair<iterator, bool> M::insert(value_type const&);
              //      5) iterator MM::insert(value_type const&);
              //
              //  where M is a std::map or std::multimap:
              //
              //      6) template <typename Iter>
              //         void M::insert(Iter first, Iter last);
  
              template <typename Sig>
              struct result;
  
              template <
                  typename This
                , typename C
                , typename Arg1
              >
              struct result<This(C &, Arg1)>
                  : result_of::insert<C, Arg1>
              {};
  
              template <
                  typename This
                , typename C
                , typename Arg1
                , typename Arg2
              >
              struct result<This(C &, Arg1, Arg2)>
                  : result_of::insert<C, Arg1, Arg2>
              {};
  
              template <
                  typename This
                , typename C
                , typename Arg1
                , typename Arg2
                , typename Arg3
              >
              struct result<This(C &, Arg1, Arg2, Arg3)>
                  : result_of::insert<C, Arg1, Arg2, Arg3>
              {};
  
              template <typename C, typename Arg1>
              typename result<insert(C&, Arg1)>::type
              operator()(C& c, Arg1 arg1) const
              {
                  return c.insert(arg1);
              }
  
              template <typename C, typename Arg1, typename Arg2>
              typename result<insert(C&, Arg1, Arg2)>::type
              operator()(C& c, Arg1 arg1, Arg2 arg2) const
              {
                  typedef typename result<insert(C&, Arg1, Arg2)>::type result_type;
                  return static_cast<result_type>(c.insert(arg1, arg2));
              }
  
              template <typename C, typename Arg1, typename Arg2, typename Arg3>
              typename result<insert(C&, Arg1, Arg2, Arg3)>::type
              operator()(C& c, Arg1 arg1, Arg2 arg2, Arg3 arg3) const
              {
                  typedef typename result<insert(C&, Arg1, Arg2, Arg3)>::type result_type;
                  return static_cast<result_type>(c.insert(arg1, arg2, arg3));
              }
          };
  
          namespace result_of
          {
              template <typename C>
              struct key_comp
              {
                  typedef typename key_compare_of<C>::type type;
              };
          }
  
          struct key_comp
          {
              template <typename Sig>
              struct result;
  
              template <typename This, typename C>
              struct result<This(C&)>
                  : result_of::key_comp<C>
              {};
  
              template <typename C>
              typename result_of::key_comp<C>::type
              operator()(C& c) const
              {
                  return c.key_comp();
              }
          };
  
          struct max_size
          {
              template <typename Sig>
              struct result;
  
              template <typename This, typename C>
              struct result<This(C&)>
              {
                  typedef typename size_type_of<C>::type type;
              };
  
              template <typename C>
              typename result<max_size(C const&)>::type
              operator()(C& c) const
              {
                  return c.max_size();
              }
          };
  
          struct pop_back
          {
              typedef void result_type;
  
              template <typename C>
              void operator()(C& c) const
              {
                  return c.pop_back();
              }
          };
  
          struct pop_front
          {
              typedef void result_type;
  
              template <typename C>
              void operator()(C& c) const
              {
                  return c.pop_front();
              }
          };
  
          struct push_back
          {
              typedef void result_type;
  
              template <typename C, typename Arg>
              void operator()(C& c, Arg const& data) const
              {
                  return c.push_back(data);
              }
          };
  
          struct push_front
          {
              typedef void result_type;
  
              template <typename C, typename Arg>
              void operator()(C& c, Arg const& data) const
              {
                  return c.push_front(data);
              }
          };
  
          struct rbegin
          {
              template <typename Sig>
              struct result;
  
              template <typename This, typename C>
              struct result<This(C&)>
              {
                  typedef typename
                      const_qualified_reverse_iterator_of<C>::type
                  type;
              };
  
              template <typename C>
              typename result<rbegin(C&)>::type
              operator()(C& c) const
              {
                  return c.rbegin();
              }
          };
  
          struct rend
          {
              template <typename Sig>
              struct result;
  
              template <typename This, typename C>
              struct result<This(C&)>
              {
                  typedef typename
                      const_qualified_reverse_iterator_of<C>::type
                  type;
              };
  
              template <typename C>
              typename result<rend(C&)>::type
              operator()(C& c) const
              {
                  return c.rend();
              }
          };
  
          struct reserve
          {
              typedef void result_type;
  
              template <typename C, typename Arg>
              void operator()(C& c, Arg const& count) const
              {
                  c.reserve(count);
              }
          };
  
          struct resize
          {
              typedef void result_type;
  
              template <typename C, typename Arg1>
              void operator()(C& c, Arg1 const& arg1) const
              {
                  c.resize(arg1);
              }
  
              template <typename C, typename Arg1, typename Arg2>
              void operator()(C& c, Arg1 const& arg1, Arg2 const& arg2) const
              {
                  c.resize(arg1, arg2);
              }
          };
  
          struct size
          {
              template <typename Sig>
              struct result;
  
              template <typename This, typename C>
              struct result<This(C&)>
              {
                  typedef typename size_type_of<C>::type type;
              };
  
              template <typename C>
              typename result<size(C&)>::type
              operator()(C& c) const
              {
                  return c.size();
              }
          };
  
      struct splice
      {
          typedef void result_type;
  
          template <typename C, typename Arg1, typename Arg2>
          void operator()(C& c, Arg1 arg1, Arg2 &arg2) const
          {
              c.splice(arg1, arg2);
          }
  
          template <
              typename C
            , typename Arg1
            , typename Arg2
            , typename Arg3
          >
          void operator()(
              C& c
            , Arg1 arg1
            , Arg2 & arg2
            , Arg3 arg3
          ) const
          {
              c.splice(arg1, arg2, arg3);
          }
  
          template <
              typename C
            , typename Arg1
            , typename Arg2
            , typename Arg3
            , typename Arg4
          >
          void operator()(
              C c
            , Arg1 arg1
            , Arg2 & arg2
            , Arg3 arg3
            , Arg4 arg4
          ) const
          {
              c.splice(arg1, arg2, arg3, arg4);
          }
      };
  
  
      namespace result_of
      {
          template <typename C>
          struct value_comp
          {
              typedef typename value_compare_of<C>::type type;
          };
      }
  
      struct value_comp
      {
          template <typename Sig>
          struct result;
  
          template <typename This, typename C>
          struct result<This(C&)>
              : result_of::value_comp<C>
          {};
  
          template <typename C>
          typename result_of::value_comp<C>::type
          operator()(C& c) const
          {
              return c.value_comp();
          }
      };
  
  } // namespace stl
  
      ///////////////////////////////////////////////////////////////////////////////
      //
      //  The lazy functions themselves.
      //
      ///////////////////////////////////////////////////////////////////////////////
      namespace adl_barrier
      {
          BOOST_PHOENIX_ADAPT_CALLABLE(assign, boost::phoenix::stl::assign, 2)
          BOOST_PHOENIX_ADAPT_CALLABLE(assign, boost::phoenix::stl::assign, 3)
          BOOST_PHOENIX_ADAPT_CALLABLE(assign, boost::phoenix::stl::assign, 4)
          BOOST_PHOENIX_ADAPT_CALLABLE(at, ::boost::phoenix::stl::at_impl, 2)
          BOOST_PHOENIX_ADAPT_CALLABLE(back, stl::back, 1)
          BOOST_PHOENIX_ADAPT_CALLABLE(begin, stl::begin, 1)
          BOOST_PHOENIX_ADAPT_CALLABLE(capacity, stl::capacity, 1)
          BOOST_PHOENIX_ADAPT_CALLABLE(clear, stl::clear, 1)
          BOOST_PHOENIX_ADAPT_CALLABLE(empty, stl::empty, 1)
          BOOST_PHOENIX_ADAPT_CALLABLE(end, stl::end, 1)
          BOOST_PHOENIX_ADAPT_CALLABLE(erase, stl::erase, 2)
          BOOST_PHOENIX_ADAPT_CALLABLE(erase, stl::erase, 3)
          BOOST_PHOENIX_ADAPT_CALLABLE(front, stl::front, 1)
          BOOST_PHOENIX_ADAPT_CALLABLE(get_allocator, stl::get_allocator, 1)
          BOOST_PHOENIX_ADAPT_CALLABLE(insert, stl::insert, 2)
          BOOST_PHOENIX_ADAPT_CALLABLE(insert, stl::insert, 3)
          BOOST_PHOENIX_ADAPT_CALLABLE(insert, stl::insert, 4)
          BOOST_PHOENIX_ADAPT_CALLABLE(key_comp, stl::key_comp, 1)
          BOOST_PHOENIX_ADAPT_CALLABLE(max_size, stl::max_size, 1)
          BOOST_PHOENIX_ADAPT_CALLABLE(pop_back, stl::pop_back, 1)
          BOOST_PHOENIX_ADAPT_CALLABLE(pop_front, stl::pop_front, 1)
          BOOST_PHOENIX_ADAPT_CALLABLE(push_back, stl::push_back, 2)
          BOOST_PHOENIX_ADAPT_CALLABLE(push_front, stl::push_front, 2)
          BOOST_PHOENIX_ADAPT_CALLABLE(rbegin, stl::rbegin, 1)
          BOOST_PHOENIX_ADAPT_CALLABLE(rend, stl::rend, 1)
          BOOST_PHOENIX_ADAPT_CALLABLE(reserve, stl::reserve, 2)
          BOOST_PHOENIX_ADAPT_CALLABLE(resize, stl::resize, 2)
          BOOST_PHOENIX_ADAPT_CALLABLE(resize, stl::resize, 3)
          BOOST_PHOENIX_ADAPT_CALLABLE(size, stl::size, 1)
          BOOST_PHOENIX_ADAPT_CALLABLE(splice, stl::splice, 2)
          BOOST_PHOENIX_ADAPT_CALLABLE(splice, stl::splice, 3)
          BOOST_PHOENIX_ADAPT_CALLABLE(splice, stl::splice, 4)
          BOOST_PHOENIX_ADAPT_CALLABLE(splice, stl::splice, 5)
          BOOST_PHOENIX_ADAPT_CALLABLE(value_comp, stl::value_comp, 1)
      }
  
      using namespace phoenix::adl_barrier;
  }} // namespace boost::phoenix
  
  #endif // BOOST_PHOENIX_STL_CONTAINERS_HPP
  