]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 : is_same<T, Attribute> {}; | |
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 | : mpl::or_< | |
79 | is_same<T, Attribute> | |
80 | , variant_has_substitute<Attribute, T> | |
81 | > | |
82 | {}; | |
83 | } | |
84 | ||
85 | template <typename T, typename Attribute, typename Enable /*= void*/> | |
86 | struct is_substitute | |
87 | : detail::is_substitute_impl<T, Attribute> {}; | |
88 | ||
89 | // for reference T | |
90 | template <typename T, typename Attribute, typename Enable> | |
91 | struct is_substitute<T&, Attribute, Enable> | |
92 | : is_substitute<T, Attribute, Enable> {}; | |
93 | ||
94 | // for reference Attribute | |
95 | template <typename T, typename Attribute, typename Enable> | |
96 | struct is_substitute<T, Attribute&, Enable> | |
97 | : is_substitute<T, Attribute, Enable> {}; | |
98 | ||
99 | // 2 element mpl tuple is compatible with fusion::map if: | |
100 | // - it's first element type is existing key in map | |
101 | // - it second element type is compatible to type stored at the key in map | |
102 | template <typename T, typename Attribute> | |
103 | struct is_substitute<T, Attribute | |
104 | , typename enable_if< | |
105 | typename mpl::eval_if< | |
106 | mpl::and_<fusion::traits::is_sequence<T> | |
107 | , fusion::traits::is_sequence<Attribute>> | |
108 | , mpl::and_<traits::has_size<T, 2> | |
109 | , fusion::traits::is_associative<Attribute>> | |
110 | , mpl::false_>::type>::type> | |
111 | ||
112 | { | |
113 | // checking that "p_key >> p_value" parser can | |
114 | // store it's result in fusion::map attribute | |
115 | typedef typename mpl::at_c<T, 0>::type p_key; | |
116 | typedef typename mpl::at_c<T, 1>::type p_value; | |
117 | ||
118 | // for simple p_key type we just check that | |
119 | // such key can be found in attr and that value under that key | |
120 | // matches p_value | |
121 | template <typename Key, typename Value, typename Map> | |
122 | struct has_kv_in_map | |
123 | : mpl::eval_if< | |
124 | fusion::result_of::has_key<Map, Key> | |
125 | , mpl::apply< | |
126 | is_substitute< | |
127 | fusion::result_of::value_at_key<mpl::_1, Key> | |
128 | , Value> | |
129 | , Map> | |
130 | , mpl::false_> | |
131 | {}; | |
132 | ||
133 | // if p_key is variant over multiple types (as a result of | |
134 | // "(key1|key2|key3) >> p_value" parser) check that all | |
135 | // keys are found in fusion::map attribute and that values | |
136 | // under these keys match p_value | |
137 | template <typename Variant> | |
138 | struct variant_kv | |
139 | : mpl::equal_to< | |
140 | mpl::size< typename Variant::types> | |
141 | , mpl::size< mpl::filter_view<typename Variant::types | |
142 | , has_kv_in_map<mpl::_1, p_value, Attribute>>> | |
143 | > | |
144 | {}; | |
145 | ||
146 | typedef typename | |
147 | mpl::eval_if< | |
148 | is_variant<p_key> | |
149 | , variant_kv<p_key> | |
150 | , has_kv_in_map<p_key, p_value, Attribute> | |
151 | >::type | |
152 | type; | |
153 | }; | |
154 | ||
155 | template <typename T, typename Attribute> | |
156 | struct is_substitute<optional<T>, optional<Attribute>> | |
157 | : is_substitute<T, Attribute> {}; | |
158 | }}}} | |
159 | ||
160 | #endif |