text: //  (C) Copyright Gennadiy Rozental 2001.
  //  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://www.boost.org/libs/test for the library home page.
  //
  //! @file
  //! Defines the is_forward_iterable collection type trait
  // ***************************************************************************
  
  #ifndef BOOST_TEST_UTILS_IS_FORWARD_ITERABLE_HPP
  #define BOOST_TEST_UTILS_IS_FORWARD_ITERABLE_HPP
  
  #if defined(BOOST_NO_CXX11_DECLTYPE) || \
      defined(BOOST_NO_CXX11_NULLPTR) || \
      defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES)
  
    // some issues with boost.config
    #if !defined(BOOST_MSVC) || BOOST_MSVC_FULL_VER < 170061030 /* VC2012 upd 5 */
      #define BOOST_TEST_FWD_ITERABLE_CXX03
    #endif
  #endif
  
  #if defined(BOOST_TEST_FWD_ITERABLE_CXX03)
  // Boost
  #include <boost/mpl/bool.hpp>
  
  // STL
  #include <list>
  #include <vector>
  #include <map>
  #include <set>
  
  #else
  
  // Boost
  #include <boost/utility/declval.hpp>
  #include <boost/type_traits/is_same.hpp>
  #include <boost/type_traits/remove_reference.hpp>
  #include <boost/type_traits/remove_cv.hpp>
  #include <boost/test/utils/is_cstring.hpp>
  
  // STL
  #include <utility>
  #include <type_traits>
  
  #endif
  //____________________________________________________________________________//
  
  namespace boost {
  namespace unit_test {
  
  // ************************************************************************** //
  // **************             is_forward_iterable              ************** //
  // ************************************************************************** //
  
  #if defined(BOOST_TEST_FWD_ITERABLE_CXX03) && !defined(BOOST_TEST_DOXYGEN_DOC__)
  template<typename T>
  struct is_forward_iterable : public mpl::false_ {};
  
  template<typename T>
  struct is_forward_iterable<T const> : public is_forward_iterable<T> {};
  
  template<typename T>
  struct is_forward_iterable<T&> : public is_forward_iterable<T> {};
  
  template<typename T, typename A>
  struct is_forward_iterable< std::vector<T, A> > : public mpl::true_ {};
  
  template<typename T, typename A>
  struct is_forward_iterable< std::list<T, A> > : public mpl::true_ {};
  
  template<typename K, typename V, typename C, typename A>
  struct is_forward_iterable< std::map<K, V, C, A> > : public mpl::true_ {};
  
  template<typename K, typename C, typename A>
  struct is_forward_iterable< std::set<K, C, A> > : public mpl::true_ {};
  
  #else
  
  namespace ut_detail {
  
  template<typename T>
  struct is_present : public mpl::true_ {};
  
  //____________________________________________________________________________//
  
  // some compiler do not implement properly decltype non expression involving members (eg. VS2013)
  // a workaround is to use -> decltype syntax.
  template <class T>
  struct has_member_size {
  private:
      struct nil_t {};
      template<typename U> static auto  test( U* ) -> decltype(boost::declval<U>().size());
      template<typename>   static nil_t test( ... );
  
  public:
      static bool const value = !std::is_same< decltype(test<T>( nullptr )), nil_t>::value;
  };
  
  //____________________________________________________________________________//
  
  template <class T>
  struct has_member_begin {
  private:
      struct nil_t {};
      template<typename U>  static auto  test( U* ) -> decltype(boost::declval<U>().begin());
      template<typename>    static nil_t test( ... );
  public:
      static bool const value = !std::is_same< decltype(test<T>( nullptr )), nil_t>::value;
  };
  
  //____________________________________________________________________________//
  
  template <class T>
  struct has_member_end {
  private:
      struct nil_t {};
      template<typename U>  static auto  test( U* ) -> decltype(boost::declval<U>().end());
      template<typename>    static nil_t test( ... );
  public:
      static bool const value = !std::is_same< decltype(test<T>( nullptr )), nil_t>::value;
  };
  
  //____________________________________________________________________________//
  
  template <class T, class enabled = void>
  struct is_forward_iterable_impl : std::false_type {
  };
  
  //____________________________________________________________________________//
  
  template <class T>
  struct is_forward_iterable_impl<
      T,
      typename std::enable_if<
      is_present<typename T::const_iterator>::value &&
      is_present<typename T::value_type>::value &&
      has_member_size<T>::value &&
      has_member_begin<T>::value &&
      has_member_end<T>::value &&
      !is_cstring<T>::value
      >::type
  > : std::true_type
  {};
  
  //____________________________________________________________________________//
  
  } // namespace ut_detail
  
  /*! Indicates that a specific type implements the forward iterable concept. */
  template<typename T>
  struct is_forward_iterable {
      typedef typename std::remove_reference<T>::type T_ref;
      typedef ut_detail::is_forward_iterable_impl<T_ref> is_fwd_it_t;
      typedef mpl::bool_<is_fwd_it_t::value> type;
      enum { value = is_fwd_it_t::value };
  };
  
  #endif /* defined(BOOST_TEST_FWD_ITERABLE_CXX03) */
  
  } // namespace unit_test
  } // namespace boost
  
  #endif // BOOST_TEST_UTILS_IS_FORWARD_ITERABLE_HPP
  