1 /*=============================================================================
2     Copyright (c) 2004 Angus Leeming
3     Copyright (c) 2004 Joel de Guzman
4 
5     Distributed under the Boost Software License, Version 1.0. (See accompanying
6     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 ==============================================================================*/
8 #ifndef BOOST_PHOENIX_CONTAINER_DETAIL_CONTAINER_HPP
9 #define BOOST_PHOENIX_CONTAINER_DETAIL_CONTAINER_HPP
10 
11 #include <utility>
12 #include <boost/mpl/eval_if.hpp>
13 #include <boost/type_traits/is_same.hpp>
14 #include <boost/type_traits/is_const.hpp>
15 #include <boost/type_traits/is_convertible.hpp>
16 
17 namespace boost { namespace phoenix { namespace stl
18 {
19 ///////////////////////////////////////////////////////////////////////////////
20 //
21 //  Metafunctions "value_type_of", "key_type_of" etc.
22 //
23 //      These metafunctions define a typedef "type" that returns the nested
24 //      type if it exists. If not then the typedef returns void.
25 //
26 //      For example, "value_type_of<std::vector<int> >::type" is "int" whilst
27 //      "value_type_of<double>::type" is "void".
28 //
29 //      I use a macro to define structs "value_type_of" etc simply to cut
30 //      down on the amount of code. The macro is #undef-ed immediately after
31 //      its final use.
32 //
33 /////////////////////////////////////////////////////////////////c//////////////
34 #define MEMBER_TYPE_OF(MEMBER_TYPE)                                             \
35     template <typename C>                                                       \
36     struct BOOST_PP_CAT(MEMBER_TYPE, _of)                                       \
37     {                                                                           \
38         typedef typename C::MEMBER_TYPE type;                                   \
39     }
40 
41     MEMBER_TYPE_OF(allocator_type);
42     MEMBER_TYPE_OF(const_iterator);
43     MEMBER_TYPE_OF(const_reference);
44     MEMBER_TYPE_OF(const_reverse_iterator);
45     MEMBER_TYPE_OF(container_type);
46     MEMBER_TYPE_OF(data_type);
47     MEMBER_TYPE_OF(iterator);
48     MEMBER_TYPE_OF(key_compare);
49     MEMBER_TYPE_OF(key_type);
50     MEMBER_TYPE_OF(reference);
51     MEMBER_TYPE_OF(reverse_iterator);
52     MEMBER_TYPE_OF(size_type);
53     MEMBER_TYPE_OF(value_compare);
54     MEMBER_TYPE_OF(value_type);
55 
56 #undef MEMBER_TYPE_OF
57 
58 ///////////////////////////////////////////////////////////////////////////////
59 //
60 //  Const-Qualified types.
61 //
62 //      Many of the stl member functions have const and non-const
63 //      overloaded versions that return distinct types. For example:
64 //
65 //          iterator begin();
66 //          const_iterator begin() const;
67 //
68 //      The three class templates defined below,
69 //      const_qualified_reference_of, const_qualified_iterator_of
70 //      and const_qualified_reverse_iterator_of provide a means to extract
71 //      this return type automatically.
72 //
73 ///////////////////////////////////////////////////////////////////////////////
74     template <typename C>
75     struct const_qualified_reference_of
76     {
77         typedef typename
78             boost::mpl::eval_if_c<
79                 boost::is_const<C>::value
80               , const_reference_of<C>
81               , reference_of<C>
82             >::type
83         type;
84     };
85 
86     template <typename C>
87     struct const_qualified_iterator_of
88     {
89         typedef typename
90             boost::mpl::eval_if_c<
91                 boost::is_const<C>::value
92               , const_iterator_of<C>
93               , iterator_of<C>
94             >::type
95         type;
96     };
97 
98     template <typename C>
99     struct const_qualified_reverse_iterator_of
100     {
101         typedef typename
102             boost::mpl::eval_if_c<
103                 boost::is_const<C>::value
104               , const_reverse_iterator_of<C>
105               , reverse_iterator_of<C>
106             >::type
107         type;
108     };
109 
110 ///////////////////////////////////////////////////////////////////////////////
111 //
112 //  has_mapped_type<C>
113 //
114 //      Given a container C, determine if it is a map, multimap, unordered_map,
115 //      or unordered_multimap by checking if it has a member type named "mapped_type".
116 //
117 ///////////////////////////////////////////////////////////////////////////////
118     namespace stl_impl
119     {
120         struct one { char a[1]; };
121         struct two { char a[2]; };
122 
123         template <typename C>
124         one has_mapped_type(typename C::mapped_type(*)());
125 
126         template <typename C>
127         two has_mapped_type(...);
128     }
129 
130     template <typename C>
131     struct has_mapped_type
132         : boost::mpl::bool_<
133             sizeof(stl_impl::has_mapped_type<C>(0)) == sizeof(stl_impl::one)
134         >
135     {};
136 
137 ///////////////////////////////////////////////////////////////////////////////
138 //
139 //  has_key_type<C>
140 //
141 //      Given a container C, determine if it is a Associative Container
142 //      by checking if it has a member type named "key_type".
143 //
144 ///////////////////////////////////////////////////////////////////////////////
145     namespace stl_impl
146     {
147         template <typename C>
148         one has_key_type(typename C::key_type(*)());
149 
150         template <typename C>
151         two has_key_type(...);
152     }
153 
154     template <typename C>
155     struct has_key_type
156         : boost::mpl::bool_<
157             sizeof(stl_impl::has_key_type<C>(0)) == sizeof(stl_impl::one)
158         >
159     {};
160 
161 ///////////////////////////////////////////////////////////////////////////////
162 //
163 //  is_key_type_of<C, Arg>
164 //
165 //      Lazy evaluation friendly predicate.
166 //
167 ///////////////////////////////////////////////////////////////////////////////
168 
169     template <typename C, typename Arg>
170     struct is_key_type_of
171         : boost::is_convertible<Arg, typename key_type_of<C>::type>
172     {};
173 
174 ///////////////////////////////////////////////////////////////////////////////
175 //
176 //  map_insert_returns_pair<C>
177 //
178 //      Distinguish a map from a multimap by checking the return type
179 //      of its "insert" member function. A map returns a pair while
180 //      a multimap returns an iterator.
181 //
182 ///////////////////////////////////////////////////////////////////////////////
183     namespace stl_impl
184     {
185         //  Cool implementation of map_insert_returns_pair by Daniel Wallin.
186         //  Thanks Daniel!!! I owe you a Pizza!
187 
188         template<class A, class B>
189         one map_insert_returns_pair_check(std::pair<A,B> const&);
190 
191         template <typename T>
192         two map_insert_returns_pair_check(T const&);
193 
194         template <typename C>
195         struct map_insert_returns_pair
196         {
197             static typename C::value_type const& get;
198             BOOST_STATIC_CONSTANT(int,
199                 value = sizeof(
200                     map_insert_returns_pair_check(((C*)0)->insert(get))));
201             typedef boost::mpl::bool_<value == sizeof(one)> type;
202         };
203     }
204 
205     template <typename C>
206     struct map_insert_returns_pair
207         : stl_impl::map_insert_returns_pair<C>::type {};
208 
209 }}} // namespace boost::phoenix::stl
210 
211 #endif // BOOST_PHOENIX_STL_CONTAINER_TRAITS_HPP
212