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 | |
219 | static const_iterator begin(T const& container) { |
220 | return container.begin(); |
221 | } |
222 | 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 |
229 | size(T const& container) { |
230 | return container.size(); |
231 | } |
232 | #else |
233 | static std::size_t |
234 | 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 |
240 | size(T const& container, std::true_type) { return container.size(); } |
241 | |
242 | static std::size_t |
243 | 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 | |
253 | static const_iterator begin(T_const (&array)[N]) { |
254 | return &array[0]; |
255 | } |
256 | static const_iterator end(T_const (&array)[N]) { |
257 | return &array[N]; |
258 | } |
259 | 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 | |