]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
11fdf7f2 | 19 | // this feature works with VC2012 upd 5 while BOOST_NO_CXX11_TRAILING_RESULT_TYPES is defined |
92f5a8d4 | 20 | #if !defined(BOOST_MSVC) || BOOST_MSVC_FULL_VER < 170061232 /* VC2012 upd 5 */ |
7c673cae FG |
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 | |
11fdf7f2 | 38 | #include <boost/static_assert.hpp> |
7c673cae FG |
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 | ||
b32b8144 FG |
55 | template<typename T> |
56 | struct is_forward_iterable; | |
57 | ||
7c673cae FG |
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 | ||
b32b8144 FG |
72 | template<typename T, std::size_t N> |
73 | struct is_forward_iterable< T [N] > : public mpl::true_ {}; | |
74 | ||
7c673cae FG |
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 | ||
b32b8144 FG |
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 | ||
7c673cae FG |
92 | #else |
93 | ||
94 | namespace ut_detail { | |
95 | ||
b32b8144 | 96 | // SFINAE helper |
7c673cae FG |
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 {}; | |
b32b8144 | 121 | template<typename U> static auto test( U* ) -> decltype(std::begin(boost::declval<U&>())); // does not work with boost::begin |
7c673cae FG |
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 {}; | |
b32b8144 | 133 | template<typename U> static auto test( U* ) -> decltype(std::end(boost::declval<U&>())); // does not work with boost::end |
7c673cae FG |
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 | ||
7c673cae FG |
145 | template <class T> |
146 | struct is_forward_iterable_impl< | |
147 | T, | |
148 | typename std::enable_if< | |
b32b8144 FG |
149 | has_member_begin<T>::value && |
150 | has_member_end<T>::value | |
7c673cae FG |
151 | >::type |
152 | > : std::true_type | |
153 | {}; | |
154 | ||
155 | //____________________________________________________________________________// | |
156 | ||
b32b8144 FG |
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 | ||
7c673cae FG |
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 | ||
b32b8144 FG |
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 | ||
7c673cae FG |
195 | #endif /* defined(BOOST_TEST_FWD_ITERABLE_CXX03) */ |
196 | ||
11fdf7f2 TL |
197 | |
198 | //! Helper structure for accessing the content of a container or an array | |
b32b8144 FG |
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 >{ | |
11fdf7f2 TL |
204 | BOOST_STATIC_ASSERT((is_forward_iterable<T>::value)); |
205 | ||
206 | #if defined(BOOST_TEST_FWD_ITERABLE_CXX03) || \ | |
92f5a8d4 | 207 | (defined(BOOST_MSVC) && (BOOST_MSVC_FULL_VER <= 170061232)) |
b32b8144 | 208 | typedef typename T::const_iterator const_iterator; |
11fdf7f2 TL |
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 */ | |
b32b8144 FG |
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 | } | |
11fdf7f2 TL |
225 | |
226 | #if defined(BOOST_TEST_FWD_ITERABLE_CXX03) || \ | |
92f5a8d4 | 227 | (defined(BOOST_MSVC) && (BOOST_MSVC_FULL_VER <= 170061232)) |
11fdf7f2 TL |
228 | static std::size_t |
229 | size(T const& container) { | |
b32b8144 FG |
230 | return container.size(); |
231 | } | |
11fdf7f2 TL |
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 */ | |
b32b8144 FG |
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 | ||
7c673cae FG |
264 | } // namespace unit_test |
265 | } // namespace boost | |
266 | ||
267 | #endif // BOOST_TEST_UTILS_IS_FORWARD_ITERABLE_HPP |