1 /*=============================================================================
2     Copyright (c) 2001-2014 Joel de Guzman
3     Copyright (c) 2001-2011 Hartmut Kaiser
4     http://spirit.sourceforge.net/
5 
6     Distributed under the Boost Software License, Version 1.0. (See accompanying
7     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 =============================================================================*/
9 #if !defined(BOOST_SPIRIT_X3_CONTAINER_FEBRUARY_06_2007_1001AM)
10 #define BOOST_SPIRIT_X3_CONTAINER_FEBRUARY_06_2007_1001AM
11 
12 #include <boost/fusion/support/category_of.hpp>
13 #include <boost/spirit/home/x3/support/unused.hpp>
14 #include <boost/fusion/include/deque.hpp>
15 #include <boost/mpl/identity.hpp>
16 #include <boost/type_traits/make_void.hpp>
17 
18 #include <vector>
19 #include <string>
20 #include <iterator>
21 #include <algorithm>
22 
23 namespace boost { namespace spirit { namespace x3 { namespace traits
24 {
25     ///////////////////////////////////////////////////////////////////////////
26     //  This file contains some container utils for stl containers.
27     ///////////////////////////////////////////////////////////////////////////
28 
29     namespace detail
30     {
31         template <typename T, typename Enabler = void>
32         struct is_container_impl : mpl::false_ {};
33 
34         template <typename T>
35         struct is_container_impl<T, void_t<
36             typename T::value_type, typename T::iterator,
37             typename T::size_type, typename T::reference> > : mpl::true_ {};
38 
39         template <typename T, typename Enabler = void>
40         struct is_associative_impl : mpl::false_ {};
41 
42         template <typename T>
43         struct is_associative_impl<T, void_t<typename T::key_type>>
44             : mpl::true_ {};
45     }
46 
47     template <typename T>
48     using is_container = typename detail::is_container_impl<T>::type;
49 
50     template <typename T>
51     using is_associative = typename detail::is_associative_impl<T>::type;
52 
53     ///////////////////////////////////////////////////////////////////////////
54     namespace detail
55     {
56         template <typename T>
57         struct remove_value_const : mpl::identity<T> {};
58 
59         template <typename T>
60         struct remove_value_const<T const> : remove_value_const<T> {};
61 
62         template <typename F, typename S>
63         struct remove_value_const<std::pair<F, S>>
64         {
65             typedef typename remove_value_const<F>::type first_type;
66             typedef typename remove_value_const<S>::type second_type;
67             typedef std::pair<first_type, second_type> type;
68         };
69     }
70 
71     ///////////////////////////////////////////////////////////////////////
72     template <typename Container, typename Enable = void>
73     struct container_value
74       : detail::remove_value_const<typename Container::value_type>
75     {};
76 
77     template <typename Container>
78     struct container_value<Container const> : container_value<Container> {};
79 
80     // There is no single container value for fusion maps, but because output
81     // of this metafunc is used to check wheter parser's attribute can be
82     // saved to container, we simply return whole fusion::map as is
83     // so that check can be done in traits::is_substitute specialisation
84     template <typename T>
85     struct container_value<T
86 			   , typename enable_if<typename mpl::eval_if <
87 						    fusion::traits::is_sequence<T>
88 						    , fusion::traits::is_associative<T>
89 						    , mpl::false_ >::type >::type>
90     : mpl::identity<T> {};
91 
92     template <>
93     struct container_value<unused_type> : mpl::identity<unused_type> {};
94 
95     ///////////////////////////////////////////////////////////////////////////
96     template <typename Container, typename Enable = void>
97     struct container_iterator
98         : mpl::identity<typename Container::iterator> {};
99 
100     template <typename Container>
101     struct container_iterator<Container const>
102          : mpl::identity<typename Container::const_iterator> {};
103 
104     template <>
105     struct container_iterator<unused_type>
106         : mpl::identity<unused_type const*> {};
107 
108     template <>
109     struct container_iterator<unused_type const>
110         : mpl::identity<unused_type const*> {};
111 
112     ///////////////////////////////////////////////////////////////////////////
113     template <typename Container, typename T>
114     bool push_back(Container& c, T&& val);
115 
116     template <typename Container, typename Enable = void>
117     struct push_back_container
118     {
119         template <typename T>
callboost::spirit::x3::traits::push_back_container120         static bool call(Container& c, T&& val)
121         {
122             c.insert(c.end(), static_cast<T&&>(val));
123             return true;
124         }
125     };
126 
127     template <typename Container, typename T>
push_back(Container & c,T && val)128     inline bool push_back(Container& c, T&& val)
129     {
130         return push_back_container<Container>::call(c, static_cast<T&&>(val));
131     }
132 
133     template <typename Container>
push_back(Container &,unused_type)134     inline bool push_back(Container&, unused_type)
135     {
136         return true;
137     }
138 
139     template <typename T>
push_back(unused_type,T &&)140     inline bool push_back(unused_type, T&&)
141     {
142         return true;
143     }
144 
push_back(unused_type,unused_type)145     inline bool push_back(unused_type, unused_type)
146     {
147         return true;
148     }
149 
150     ///////////////////////////////////////////////////////////////////////////
151     template <typename Container, typename Iterator>
152     bool append(Container& c, Iterator first, Iterator last);
153 
154     template <typename Container, typename Enable = void>
155     struct append_container
156     {
157     private:
158         template <typename Iterator>
insertboost::spirit::x3::traits::append_container159         static void insert(Container& c, Iterator first, Iterator last, mpl::false_)
160         {
161             c.insert(c.end(), first, last);
162         }
163 
164         template <typename Iterator>
insertboost::spirit::x3::traits::append_container165         static void insert(Container& c, Iterator first, Iterator last, mpl::true_)
166         {
167             c.insert(first, last);
168         }
169 
170     public:
171         template <typename Iterator>
callboost::spirit::x3::traits::append_container172         static bool call(Container& c, Iterator first, Iterator last)
173         {
174             insert(c, first, last, is_associative<Container>{});
175             return true;
176         }
177     };
178 
179     template <typename Container, typename Iterator>
append(Container & c,Iterator first,Iterator last)180     inline bool append(Container& c, Iterator first, Iterator last)
181     {
182         return append_container<Container>::call(c, first, last);
183     }
184 
185     template <typename Iterator>
append(unused_type,Iterator,Iterator)186     inline bool append(unused_type, Iterator /* first */, Iterator /* last */)
187     {
188         return true;
189     }
190 
191     ///////////////////////////////////////////////////////////////////////////
192     template <typename Container, typename Enable = void>
193     struct is_empty_container
194     {
callboost::spirit::x3::traits::is_empty_container195         static bool call(Container const& c)
196         {
197             return c.empty();
198         }
199     };
200 
201     template <typename Container>
is_empty(Container const & c)202     inline bool is_empty(Container const& c)
203     {
204         return is_empty_container<Container>::call(c);
205     }
206 
is_empty(unused_type)207     inline bool is_empty(unused_type)
208     {
209         return true;
210     }
211 
212     ///////////////////////////////////////////////////////////////////////////
213     template <typename Container, typename Enable = void>
214     struct begin_container
215     {
callboost::spirit::x3::traits::begin_container216         static typename container_iterator<Container>::type call(Container& c)
217         {
218             return c.begin();
219         }
220     };
221 
222     template <typename Container>
223     inline typename container_iterator<Container>::type
begin(Container & c)224     begin(Container& c)
225     {
226         return begin_container<Container>::call(c);
227     }
228 
229     inline unused_type const*
begin(unused_type)230     begin(unused_type)
231     {
232         return &unused;
233     }
234 
235     ///////////////////////////////////////////////////////////////////////////
236     template <typename Container, typename Enable = void>
237     struct end_container
238     {
callboost::spirit::x3::traits::end_container239         static typename container_iterator<Container>::type call(Container& c)
240         {
241             return c.end();
242         }
243     };
244 
245     template <typename Container>
246     inline typename container_iterator<Container>::type
end(Container & c)247     end(Container& c)
248     {
249         return end_container<Container>::call(c);
250     }
251 
252     inline unused_type const*
end(unused_type)253     end(unused_type)
254     {
255         return &unused;
256     }
257 
258 
259     ///////////////////////////////////////////////////////////////////////////
260     template <typename Iterator, typename Enable = void>
261     struct deref_iterator
262     {
263         typedef typename std::iterator_traits<Iterator>::reference type;
callboost::spirit::x3::traits::deref_iterator264         static type call(Iterator& it)
265         {
266             return *it;
267         }
268     };
269 
270     template <typename Iterator>
271     typename deref_iterator<Iterator>::type
deref(Iterator & it)272     deref(Iterator& it)
273     {
274         return deref_iterator<Iterator>::call(it);
275     }
276 
277     inline unused_type
deref(unused_type const *)278     deref(unused_type const*)
279     {
280         return unused;
281     }
282 
283     ///////////////////////////////////////////////////////////////////////////
284     template <typename Iterator, typename Enable = void>
285     struct next_iterator
286     {
callboost::spirit::x3::traits::next_iterator287         static void call(Iterator& it)
288         {
289             ++it;
290         }
291     };
292 
293     template <typename Iterator>
next(Iterator & it)294     void next(Iterator& it)
295     {
296         next_iterator<Iterator>::call(it);
297     }
298 
next(unused_type const *)299     inline void next(unused_type const*)
300     {
301         // do nothing
302     }
303 
304     ///////////////////////////////////////////////////////////////////////////
305     template <typename Iterator, typename Enable = void>
306     struct compare_iterators
307     {
callboost::spirit::x3::traits::compare_iterators308         static bool call(Iterator const& it1, Iterator const& it2)
309         {
310             return it1 == it2;
311         }
312     };
313 
314     template <typename Iterator>
compare(Iterator & it1,Iterator & it2)315     bool compare(Iterator& it1, Iterator& it2)
316     {
317         return compare_iterators<Iterator>::call(it1, it2);
318     }
319 
compare(unused_type const *,unused_type const *)320     inline bool compare(unused_type const*, unused_type const*)
321     {
322         return false;
323     }
324 
325     ///////////////////////////////////////////////////////////////////////////
326     template <typename T>
327     struct build_container : mpl::identity<std::vector<T>> {};
328 
329     template <typename T>
330     struct build_container<boost::fusion::deque<T> > : build_container<T> {};
331 
332     template <>
333     struct build_container<unused_type> : mpl::identity<unused_type> {};
334 
335     template <>
336     struct build_container<char> : mpl::identity<std::string> {};
337 
338 }}}}
339 
340 #endif
341