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 | // some issues with boost.config |
20 | #if !defined(BOOST_MSVC) || BOOST_MSVC_FULL_VER < 170061030 /* 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/utility/declval.hpp> |
39 | #include <boost/type_traits/is_same.hpp> |
40 | #include <boost/type_traits/remove_reference.hpp> |
41 | #include <boost/type_traits/remove_cv.hpp> |
42 | #include <boost/test/utils/is_cstring.hpp> |
43 | |
44 | // STL |
45 | #include <utility> |
46 | #include <type_traits> |
47 | |
48 | #endif |
49 | //____________________________________________________________________________// |
50 | |
51 | namespace boost { |
52 | namespace unit_test { |
53 | |
54 | // ************************************************************************** // |
55 | // ************** is_forward_iterable ************** // |
56 | // ************************************************************************** // |
57 | |
58 | #if defined(BOOST_TEST_FWD_ITERABLE_CXX03) && !defined(BOOST_TEST_DOXYGEN_DOC__) |
59 | template<typename T> |
60 | struct is_forward_iterable : public mpl::false_ {}; |
61 | |
62 | template<typename T> |
63 | struct is_forward_iterable<T const> : public is_forward_iterable<T> {}; |
64 | |
65 | template<typename T> |
66 | struct is_forward_iterable<T&> : public is_forward_iterable<T> {}; |
67 | |
68 | template<typename T, typename A> |
69 | struct is_forward_iterable< std::vector<T, A> > : public mpl::true_ {}; |
70 | |
71 | template<typename T, typename A> |
72 | struct is_forward_iterable< std::list<T, A> > : public mpl::true_ {}; |
73 | |
74 | template<typename K, typename V, typename C, typename A> |
75 | struct is_forward_iterable< std::map<K, V, C, A> > : public mpl::true_ {}; |
76 | |
77 | template<typename K, typename C, typename A> |
78 | struct is_forward_iterable< std::set<K, C, A> > : public mpl::true_ {}; |
79 | |
80 | #else |
81 | |
82 | namespace ut_detail { |
83 | |
84 | template<typename T> |
85 | struct is_present : public mpl::true_ {}; |
86 | |
87 | //____________________________________________________________________________// |
88 | |
89 | // some compiler do not implement properly decltype non expression involving members (eg. VS2013) |
90 | // a workaround is to use -> decltype syntax. |
91 | template <class T> |
92 | struct has_member_size { |
93 | private: |
94 | struct nil_t {}; |
95 | template<typename U> static auto test( U* ) -> decltype(boost::declval<U>().size()); |
96 | template<typename> static nil_t test( ... ); |
97 | |
98 | public: |
99 | static bool const value = !std::is_same< decltype(test<T>( nullptr )), nil_t>::value; |
100 | }; |
101 | |
102 | //____________________________________________________________________________// |
103 | |
104 | template <class T> |
105 | struct has_member_begin { |
106 | private: |
107 | struct nil_t {}; |
108 | template<typename U> static auto test( U* ) -> decltype(boost::declval<U>().begin()); |
109 | template<typename> static nil_t test( ... ); |
110 | public: |
111 | static bool const value = !std::is_same< decltype(test<T>( nullptr )), nil_t>::value; |
112 | }; |
113 | |
114 | //____________________________________________________________________________// |
115 | |
116 | template <class T> |
117 | struct has_member_end { |
118 | private: |
119 | struct nil_t {}; |
120 | template<typename U> static auto test( U* ) -> decltype(boost::declval<U>().end()); |
121 | template<typename> static nil_t test( ... ); |
122 | public: |
123 | static bool const value = !std::is_same< decltype(test<T>( nullptr )), nil_t>::value; |
124 | }; |
125 | |
126 | //____________________________________________________________________________// |
127 | |
128 | template <class T, class enabled = void> |
129 | struct is_forward_iterable_impl : std::false_type { |
130 | }; |
131 | |
132 | //____________________________________________________________________________// |
133 | |
134 | template <class T> |
135 | struct is_forward_iterable_impl< |
136 | T, |
137 | typename std::enable_if< |
138 | is_present<typename T::const_iterator>::value && |
139 | is_present<typename T::value_type>::value && |
140 | has_member_size<T>::value && |
141 | has_member_begin<T>::value && |
142 | has_member_end<T>::value && |
143 | !is_cstring<T>::value |
144 | >::type |
145 | > : std::true_type |
146 | {}; |
147 | |
148 | //____________________________________________________________________________// |
149 | |
150 | } // namespace ut_detail |
151 | |
152 | /*! Indicates that a specific type implements the forward iterable concept. */ |
153 | template<typename T> |
154 | struct is_forward_iterable { |
155 | typedef typename std::remove_reference<T>::type T_ref; |
156 | typedef ut_detail::is_forward_iterable_impl<T_ref> is_fwd_it_t; |
157 | typedef mpl::bool_<is_fwd_it_t::value> type; |
158 | enum { value = is_fwd_it_t::value }; |
159 | }; |
160 | |
161 | #endif /* defined(BOOST_TEST_FWD_ITERABLE_CXX03) */ |
162 | |
163 | } // namespace unit_test |
164 | } // namespace boost |
165 | |
166 | #endif // BOOST_TEST_UTILS_IS_FORWARD_ITERABLE_HPP |
167 | |