1 // (C) Copyright Gennadiy Rozental 2001. 2 // Distributed under the Boost Software License, Version 1.0. 3 // (See accompanying file LICENSE_1_0.txt or copy at 4 // http://www.boost.org/LICENSE_1_0.txt) 5 6 // See http://www.boost.org/libs/test for the library home page. 7 // 8 //! @file 9 //! Defines the is_forward_iterable collection type trait 10 // *************************************************************************** 11 12 #ifndef BOOST_TEST_UTILS_IS_FORWARD_ITERABLE_HPP 13 #define BOOST_TEST_UTILS_IS_FORWARD_ITERABLE_HPP 14 15 #if defined(BOOST_NO_CXX11_DECLTYPE) || \ 16 defined(BOOST_NO_CXX11_NULLPTR) || \ 17 defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) 18 19 // this feature works with VC2012 upd 5 while BOOST_NO_CXX11_TRAILING_RESULT_TYPES is defined 20 #if !defined(BOOST_MSVC) || BOOST_MSVC_FULL_VER < 170061232 /* VC2012 upd 5 */ 21 #define BOOST_TEST_FWD_ITERABLE_CXX03 22 #endif 23 #endif 24 25 #if defined(BOOST_TEST_FWD_ITERABLE_CXX03) 26 // Boost 27 #include <boost/mpl/bool.hpp> 28 29 // STL 30 #include <list> 31 #include <vector> 32 #include <map> 33 #include <set> 34 35 #else 36 37 // Boost 38 #include <boost/static_assert.hpp> 39 #include <boost/utility/declval.hpp> 40 #include <boost/type_traits/is_same.hpp> 41 #include <boost/type_traits/remove_reference.hpp> 42 #include <boost/type_traits/remove_cv.hpp> 43 #include <boost/test/utils/is_cstring.hpp> 44 45 // STL 46 #include <utility> 47 #include <type_traits> 48 49 #endif 50 //____________________________________________________________________________// 51 52 namespace boost { 53 namespace unit_test { 54 55 template<typename T> 56 struct is_forward_iterable; 57 58 // ************************************************************************** // 59 // ************** is_forward_iterable ************** // 60 // ************************************************************************** // 61 62 #if defined(BOOST_TEST_FWD_ITERABLE_CXX03) && !defined(BOOST_TEST_DOXYGEN_DOC__) 63 template<typename T> 64 struct is_forward_iterable : public mpl::false_ {}; 65 66 template<typename T> 67 struct is_forward_iterable<T const> : public is_forward_iterable<T> {}; 68 69 template<typename T> 70 struct is_forward_iterable<T&> : public is_forward_iterable<T> {}; 71 72 template<typename T, std::size_t N> 73 struct is_forward_iterable< T [N] > : public mpl::true_ {}; 74 75 template<typename T, typename A> 76 struct is_forward_iterable< std::vector<T, A> > : public mpl::true_ {}; 77 78 template<typename T, typename A> 79 struct is_forward_iterable< std::list<T, A> > : public mpl::true_ {}; 80 81 template<typename K, typename V, typename C, typename A> 82 struct is_forward_iterable< std::map<K, V, C, A> > : public mpl::true_ {}; 83 84 template<typename K, typename C, typename A> 85 struct is_forward_iterable< std::set<K, C, A> > : public mpl::true_ {}; 86 87 // string is also forward iterable, even if sometimes we want to treat the 88 // assertions differently. 89 template<> 90 struct is_forward_iterable< std::string > : public mpl::true_ {}; 91 92 #else 93 94 namespace ut_detail { 95 96 // SFINAE helper 97 template<typename T> 98 struct is_present : public mpl::true_ {}; 99 100 //____________________________________________________________________________// 101 102 // some compiler do not implement properly decltype non expression involving members (eg. VS2013) 103 // a workaround is to use -> decltype syntax. 104 template <class T> 105 struct has_member_size { 106 private: 107 struct nil_t {}; 108 template<typename U> static auto test( U* ) -> decltype(boost::declval<U>().size()); 109 template<typename> static nil_t test( ... ); 110 111 public: 112 static bool const value = !std::is_same< decltype(test<T>( nullptr )), nil_t>::value; 113 }; 114 115 //____________________________________________________________________________// 116 117 template <class T> 118 struct has_member_begin { 119 private: 120 struct nil_t {}; 121 template<typename U> static auto test( U* ) -> decltype(std::begin(boost::declval<U&>())); // does not work with boost::begin 122 template<typename> static nil_t test( ... ); 123 public: 124 static bool const value = !std::is_same< decltype(test<T>( nullptr )), nil_t>::value; 125 }; 126 127 //____________________________________________________________________________// 128 129 template <class T> 130 struct has_member_end { 131 private: 132 struct nil_t {}; 133 template<typename U> static auto test( U* ) -> decltype(std::end(boost::declval<U&>())); // does not work with boost::end 134 template<typename> static nil_t test( ... ); 135 public: 136 static bool const value = !std::is_same< decltype(test<T>( nullptr )), nil_t>::value; 137 }; 138 139 //____________________________________________________________________________// 140 141 template <class T, class enabled = void> 142 struct is_forward_iterable_impl : std::false_type { 143 }; 144 145 template <class T> 146 struct is_forward_iterable_impl< 147 T, 148 typename std::enable_if< 149 has_member_begin<T>::value && 150 has_member_end<T>::value 151 >::type 152 > : std::true_type 153 {}; 154 155 //____________________________________________________________________________// 156 157 template <class T, class enabled = void> 158 struct is_container_forward_iterable_impl : std::false_type { 159 }; 160 161 template <class T> 162 struct is_container_forward_iterable_impl< 163 T, 164 typename std::enable_if< 165 is_present<typename T::const_iterator>::value && 166 is_present<typename T::value_type>::value && 167 has_member_size<T>::value && 168 is_forward_iterable_impl<T>::value 169 >::type 170 > : is_forward_iterable_impl<T> 171 {}; 172 173 //____________________________________________________________________________// 174 175 } // namespace ut_detail 176 177 /*! Indicates that a specific type implements the forward iterable concept. */ 178 template<typename T> 179 struct is_forward_iterable { 180 typedef typename std::remove_reference<T>::type T_ref; 181 typedef ut_detail::is_forward_iterable_impl<T_ref> is_fwd_it_t; 182 typedef mpl::bool_<is_fwd_it_t::value> type; 183 enum { value = is_fwd_it_t::value }; 184 }; 185 186 /*! Indicates that a specific type implements the forward iterable concept. */ 187 template<typename T> 188 struct is_container_forward_iterable { 189 typedef typename std::remove_reference<T>::type T_ref; 190 typedef ut_detail::is_container_forward_iterable_impl<T_ref> is_fwd_it_t; 191 typedef mpl::bool_<is_fwd_it_t::value> type; 192 enum { value = is_fwd_it_t::value }; 193 }; 194 195 #endif /* defined(BOOST_TEST_FWD_ITERABLE_CXX03) */ 196 197 198 //! Helper structure for accessing the content of a container or an array 199 template <typename T, bool is_forward_iterable = is_forward_iterable<T>::value > 200 struct bt_iterator_traits; 201 202 template <typename T> 203 struct bt_iterator_traits< T, true >{ 204 BOOST_STATIC_ASSERT((is_forward_iterable<T>::value)); 205 206 #if defined(BOOST_TEST_FWD_ITERABLE_CXX03) || \ 207 (defined(BOOST_MSVC) && (BOOST_MSVC_FULL_VER <= 170061232)) 208 typedef typename T::const_iterator const_iterator; 209 typedef typename std::iterator_traits<const_iterator>::value_type value_type; 210 #else 211 typedef decltype(boost::declval< 212 typename boost::add_const< 213 typename boost::remove_reference<T>::type 214 >::type>().begin()) const_iterator; 215 216 typedef typename std::iterator_traits<const_iterator>::value_type value_type; 217 #endif /* BOOST_TEST_FWD_ITERABLE_CXX03 */ 218 beginboost::unit_test::bt_iterator_traits219 static const_iterator begin(T const& container) { 220 return container.begin(); 221 } endboost::unit_test::bt_iterator_traits222 static const_iterator end(T const& container) { 223 return container.end(); 224 } 225 226 #if defined(BOOST_TEST_FWD_ITERABLE_CXX03) || \ 227 (defined(BOOST_MSVC) && (BOOST_MSVC_FULL_VER <= 170061232)) 228 static std::size_t sizeboost::unit_test::bt_iterator_traits229 size(T const& container) { 230 return container.size(); 231 } 232 #else 233 static std::size_t sizeboost::unit_test::bt_iterator_traits234 size(T const& container) { 235 return size(container, 236 std::integral_constant<bool, ut_detail::has_member_size<T>::value>()); 237 } 238 private: 239 static std::size_t sizeboost::unit_test::bt_iterator_traits240 size(T const& container, std::true_type) { return container.size(); } 241 242 static std::size_t sizeboost::unit_test::bt_iterator_traits243 size(T const& container, std::false_type) { return std::distance(begin(container), end(container)); } 244 #endif /* BOOST_TEST_FWD_ITERABLE_CXX03 */ 245 }; 246 247 template <typename T, std::size_t N> 248 struct bt_iterator_traits< T [N], true > { 249 typedef typename boost::add_const<T>::type T_const; 250 typedef typename boost::add_pointer<T_const>::type const_iterator; 251 typedef T value_type; 252 beginboost::unit_test::bt_iterator_traits253 static const_iterator begin(T_const (&array)[N]) { 254 return &array[0]; 255 } endboost::unit_test::bt_iterator_traits256 static const_iterator end(T_const (&array)[N]) { 257 return &array[N]; 258 } sizeboost::unit_test::bt_iterator_traits259 static std::size_t size(T_const (&)[N]) { 260 return N; 261 } 262 }; 263 264 } // namespace unit_test 265 } // namespace boost 266 267 #endif // BOOST_TEST_UTILS_IS_FORWARD_ITERABLE_HPP 268