• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2001-2014 Joel de Guzman
3     http://spirit.sourceforge.net/
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 #if !defined(BOOST_SPIRIT_X3_IS_SUBSTITUTE_JAN_9_2012_1049PM)
9 #define BOOST_SPIRIT_X3_IS_SUBSTITUTE_JAN_9_2012_1049PM
10 
11 #include <boost/spirit/home/x3/support/traits/container_traits.hpp>
12 #include <boost/fusion/include/is_sequence.hpp>
13 #include <boost/fusion/include/map.hpp>
14 #include <boost/fusion/include/value_at_key.hpp>
15 #include <boost/fusion/adapted/mpl.hpp>
16 #include <boost/mpl/placeholders.hpp>
17 #include <boost/mpl/equal.hpp>
18 #include <boost/mpl/apply.hpp>
19 #include <boost/mpl/filter_view.hpp>
20 #include <boost/mpl/size.hpp>
21 #include <boost/mpl/logical.hpp>
22 #include <boost/mpl/at.hpp>
23 #include <boost/mpl/count_if.hpp>
24 #include <boost/utility/enable_if.hpp>
25 #include <boost/optional/optional.hpp>
26 #include <boost/type_traits/is_same.hpp>
27 
28 namespace boost { namespace spirit { namespace x3 { namespace traits
29 {
30     ///////////////////////////////////////////////////////////////////////////
31     // Find out if T can be a (strong) substitute for Attribute
32     ///////////////////////////////////////////////////////////////////////////
33     template <typename T, typename Attribute, typename Enable = void>
34     struct is_substitute;
35 
36     template <typename Variant, typename Attribute>
37     struct variant_has_substitute;
38 
39     namespace detail
40     {
41         template <typename T, typename Attribute>
42         struct value_type_is_substitute
43           : is_substitute<
44                 typename container_value<T>::type
45               , typename container_value<Attribute>::type>
46         {};
47 
48         template <typename T, typename Attribute, typename Enable = void>
49         struct is_substitute_impl : mpl::false_ {};
50 
51         template <typename T, typename Attribute>
52         struct is_substitute_impl<T, Attribute,
53             typename enable_if<
54                 mpl::and_<
55                     fusion::traits::is_sequence<T>,
56                     fusion::traits::is_sequence<Attribute>,
57                     mpl::equal<T, Attribute, is_substitute<mpl::_1, mpl::_2>>
58                 >
59             >::type>
60           : mpl::true_ {};
61 
62         template <typename T, typename Attribute>
63         struct is_substitute_impl<T, Attribute,
64             typename enable_if<
65                 mpl::and_<
66                     is_container<T>,
67                     is_container<Attribute>,
68                     value_type_is_substitute<T, Attribute>
69                 >
70             >::type>
71           : mpl::true_ {};
72 
73         template <typename T, typename Attribute>
74         struct is_substitute_impl<T, Attribute,
75             typename enable_if<
76                 is_variant<Attribute>
77             >::type>
78           : variant_has_substitute<Attribute, T>
79         {};
80     }
81 
82     template <typename T, typename Attribute, typename Enable /*= void*/>
83     struct is_substitute
84         : mpl::or_<
85               is_same<T, Attribute>,
86               detail::is_substitute_impl<T, Attribute>> {};
87 
88     // for reference T
89     template <typename T, typename Attribute, typename Enable>
90     struct is_substitute<T&, Attribute, Enable>
91         : is_substitute<T, Attribute, Enable> {};
92 
93     // for reference Attribute
94     template <typename T, typename Attribute, typename Enable>
95     struct is_substitute<T, Attribute&, Enable>
96         : is_substitute<T, Attribute, Enable> {};
97 
98     // 2 element mpl tuple is compatible with fusion::map if:
99     // - it's first element type is existing key in map
100     // - it second element type is compatible to type stored at the key in map
101     template <typename T, typename Attribute>
102     struct is_substitute<T, Attribute
103 	, typename enable_if<
104 	      typename mpl::eval_if<
105 		  mpl::and_<fusion::traits::is_sequence<T>
106 			    , fusion::traits::is_sequence<Attribute>>
107 		  , mpl::and_<traits::has_size<T, 2>
108 			   , fusion::traits::is_associative<Attribute>>
109 		  , mpl::false_>::type>::type>
110 
111     {
112         // checking that "p_key >> p_value" parser can
113         // store it's result in fusion::map attribute
114         typedef typename mpl::at_c<T, 0>::type p_key;
115         typedef typename mpl::at_c<T, 1>::type p_value;
116 
117         // for simple p_key type we just check that
118         // such key can be found in attr and that value under that key
119         // matches p_value
120         template <typename Key, typename Value, typename Map>
121         struct has_kv_in_map
122             : mpl::eval_if<
123                 fusion::result_of::has_key<Map, Key>
124               , mpl::apply<
125                     is_substitute<
126                         fusion::result_of::value_at_key<mpl::_1, Key>
127                       , Value>
128                       , Map>
129               , mpl::false_>
130         {};
131 
132         // if p_key is variant over multiple types (as a result of
133         // "(key1|key2|key3) >> p_value" parser) check that all
134         // keys are found in fusion::map attribute and that values
135         // under these keys match p_value
136         template <typename Variant>
137         struct variant_kv
138             : mpl::equal_to<
139                 mpl::size< typename Variant::types>
140               , mpl::size< mpl::filter_view<typename Variant::types
141               , has_kv_in_map<mpl::_1, p_value, Attribute>>>
142             >
143         {};
144 
145         typedef typename
146             mpl::eval_if<
147                 is_variant<p_key>
148               , variant_kv<p_key>
149               , has_kv_in_map<p_key, p_value, Attribute>
150             >::type
151         type;
152     };
153 
154     template <typename T, typename Attribute>
155     struct is_substitute<optional<T>, optional<Attribute>>
156       : is_substitute<T, Attribute> {};
157 }}}}
158 
159 #endif
160