// (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 // STL #include #include #include #include #else // Boost #include #include #include #include #include #include // STL #include #include #endif //____________________________________________________________________________// namespace boost { namespace unit_test { template struct is_forward_iterable; // ************************************************************************** // // ************** is_forward_iterable ************** // // ************************************************************************** // #if defined(BOOST_TEST_FWD_ITERABLE_CXX03) && !defined(BOOST_TEST_DOXYGEN_DOC__) template struct is_forward_iterable : public mpl::false_ {}; template struct is_forward_iterable : public is_forward_iterable {}; template struct is_forward_iterable : public is_forward_iterable {}; template struct is_forward_iterable< T [N] > : public mpl::true_ {}; template struct is_forward_iterable< std::vector > : public mpl::true_ {}; template struct is_forward_iterable< std::list > : public mpl::true_ {}; template struct is_forward_iterable< std::map > : public mpl::true_ {}; template struct is_forward_iterable< std::set > : public mpl::true_ {}; // string is also forward iterable, even if sometimes we want to treat the // assertions differently. template<> struct is_forward_iterable< std::string > : public mpl::true_ {}; #else namespace ut_detail { // SFINAE helper template 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 struct has_member_size { private: struct nil_t {}; template static auto test( U* ) -> decltype(boost::declval().size()); template static nil_t test( ... ); public: static bool const value = !std::is_same< decltype(test( nullptr )), nil_t>::value; }; //____________________________________________________________________________// template struct has_member_begin { private: struct nil_t {}; template static auto test( U* ) -> decltype(std::begin(boost::declval())); // does not work with boost::begin template static nil_t test( ... ); public: static bool const value = !std::is_same< decltype(test( nullptr )), nil_t>::value; }; //____________________________________________________________________________// template struct has_member_end { private: struct nil_t {}; template static auto test( U* ) -> decltype(std::end(boost::declval())); // does not work with boost::end template static nil_t test( ... ); public: static bool const value = !std::is_same< decltype(test( nullptr )), nil_t>::value; }; //____________________________________________________________________________// template struct is_forward_iterable_impl : std::false_type { }; template struct is_forward_iterable_impl< T, typename std::enable_if< has_member_begin::value && has_member_end::value >::type > : std::true_type {}; //____________________________________________________________________________// template struct is_container_forward_iterable_impl : std::false_type { }; template struct is_container_forward_iterable_impl< T, typename std::enable_if< is_present::value && is_present::value && has_member_size::value && is_forward_iterable_impl::value >::type > : is_forward_iterable_impl {}; //____________________________________________________________________________// } // namespace ut_detail /*! Indicates that a specific type implements the forward iterable concept. */ template struct is_forward_iterable { typedef typename std::remove_reference::type T_ref; typedef ut_detail::is_forward_iterable_impl is_fwd_it_t; typedef mpl::bool_ type; enum { value = is_fwd_it_t::value }; }; /*! Indicates that a specific type implements the forward iterable concept. */ template struct is_container_forward_iterable { typedef typename std::remove_reference::type T_ref; typedef ut_detail::is_container_forward_iterable_impl is_fwd_it_t; typedef mpl::bool_ type; enum { value = is_fwd_it_t::value }; }; #endif /* defined(BOOST_TEST_FWD_ITERABLE_CXX03) */ template ::value > struct bt_iterator_traits; template struct bt_iterator_traits< T, true >{ BOOST_STATIC_ASSERT((is_forward_iterable::value)); //, "only for forward iterable types"); typedef typename T::const_iterator const_iterator; typedef typename T::value_type value_type; static const_iterator begin(T const& container) { return container.begin(); } static const_iterator end(T const& container) { return container.end(); } static std::size_t size(T const& container) { return container.size(); } }; template struct bt_iterator_traits< T [N], true > { typedef typename boost::add_const::type T_const; typedef typename boost::add_pointer::type const_iterator; typedef T value_type; static const_iterator begin(T_const (&array)[N]) { return &array[0]; } static const_iterator end(T_const (&array)[N]) { return &array[N]; } static std::size_t size(T_const (&)[N]) { return N; } }; } // namespace unit_test } // namespace boost #endif // BOOST_TEST_UTILS_IS_FORWARD_ITERABLE_HPP