is_substitute.hpp 5.8 KB

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