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