summaryrefslogtreecommitdiff
path: root/boost/spirit/home/x3/support/traits/is_substitute.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/spirit/home/x3/support/traits/is_substitute.hpp')
-rw-r--r--boost/spirit/home/x3/support/traits/is_substitute.hpp164
1 files changed, 164 insertions, 0 deletions
diff --git a/boost/spirit/home/x3/support/traits/is_substitute.hpp b/boost/spirit/home/x3/support/traits/is_substitute.hpp
new file mode 100644
index 0000000000..9e023371ce
--- /dev/null
+++ b/boost/spirit/home/x3/support/traits/is_substitute.hpp
@@ -0,0 +1,164 @@
+/*=============================================================================
+ Copyright (c) 2001-2014 Joel de Guzman
+ http://spirit.sourceforge.net/
+
+ Distributed under the Boost Software License, Version 1.0. (See accompanying
+ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+=============================================================================*/
+#if !defined(BOOST_SPIRIT_X3_IS_SUBSTITUTE_JAN_9_2012_1049PM)
+#define BOOST_SPIRIT_X3_IS_SUBSTITUTE_JAN_9_2012_1049PM
+
+#if defined(_MSC_VER)
+#pragma once
+#endif
+
+#include <boost/spirit/home/x3/support/traits/container_traits.hpp>
+#include <boost/fusion/include/is_sequence.hpp>
+#include <boost/fusion/include/map.hpp>
+#include <boost/fusion/include/value_at_key.hpp>
+#include <boost/fusion/adapted/mpl.hpp>
+#include <boost/mpl/placeholders.hpp>
+#include <boost/mpl/equal.hpp>
+#include <boost/mpl/apply.hpp>
+#include <boost/mpl/filter_view.hpp>
+#include <boost/mpl/size.hpp>
+#include <boost/mpl/logical.hpp>
+#include <boost/mpl/at.hpp>
+#include <boost/mpl/count_if.hpp>
+#include <boost/utility/enable_if.hpp>
+#include <boost/optional/optional.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+namespace boost { namespace spirit { namespace x3 { namespace traits
+{
+ ///////////////////////////////////////////////////////////////////////////
+ // Find out if T can be a (strong) substitute for Attribute
+ ///////////////////////////////////////////////////////////////////////////
+ template <typename T, typename Attribute, typename Enable = void>
+ struct is_substitute;
+
+ template <typename Variant, typename Attribute>
+ struct variant_has_substitute;
+
+ namespace detail
+ {
+ template <typename T, typename Attribute>
+ struct value_type_is_substitute
+ : is_substitute<
+ typename container_value<T>::type
+ , typename container_value<Attribute>::type>
+ {};
+
+ template <typename T, typename Attribute, typename Enable = void>
+ struct is_substitute_impl : is_same<T, Attribute> {};
+
+ template <typename T, typename Attribute>
+ struct is_substitute_impl<T, Attribute,
+ typename enable_if<
+ mpl::and_<
+ fusion::traits::is_sequence<T>,
+ fusion::traits::is_sequence<Attribute>,
+ mpl::equal<T, Attribute, is_substitute<mpl::_1, mpl::_2>>
+ >
+ >::type>
+ : mpl::true_ {};
+
+ template <typename T, typename Attribute>
+ struct is_substitute_impl<T, Attribute,
+ typename enable_if<
+ mpl::and_<
+ is_container<T>,
+ is_container<Attribute>,
+ value_type_is_substitute<T, Attribute>
+ >
+ >::type>
+ : mpl::true_ {};
+
+ template <typename T, typename Attribute>
+ struct is_substitute_impl<T, Attribute,
+ typename enable_if<
+ is_variant<Attribute>
+ >::type>
+ : mpl::or_<
+ is_same<T, Attribute>
+ , variant_has_substitute<Attribute, T>
+ >
+ {};
+ }
+
+ template <typename T, typename Attribute, typename Enable /*= void*/>
+ struct is_substitute
+ : detail::is_substitute_impl<T, Attribute> {};
+
+ // for reference T
+ template <typename T, typename Attribute, typename Enable>
+ struct is_substitute<T&, Attribute, Enable>
+ : is_substitute<T, Attribute, Enable> {};
+
+ // for reference Attribute
+ template <typename T, typename Attribute, typename Enable>
+ struct is_substitute<T, Attribute&, Enable>
+ : is_substitute<T, Attribute, Enable> {};
+
+ // 2 element mpl tuple is compatible with fusion::map if:
+ // - it's first element type is existing key in map
+ // - it second element type is compatible to type stored at the key in map
+ template <typename T, typename Attribute>
+ struct is_substitute<T, Attribute
+ , typename enable_if<
+ typename mpl::eval_if<
+ mpl::and_<fusion::traits::is_sequence<T>
+ , fusion::traits::is_sequence<Attribute>>
+ , mpl::and_<traits::has_size<T, 2>
+ , fusion::traits::is_associative<Attribute>>
+ , mpl::false_>::type>::type>
+
+ {
+ // checking that "p_key >> p_value" parser can
+ // store it's result in fusion::map attribute
+ typedef typename mpl::at_c<T, 0>::type p_key;
+ typedef typename mpl::at_c<T, 1>::type p_value;
+
+ // for simple p_key type we just check that
+ // such key can be found in attr and that value under that key
+ // matches p_value
+ template <typename Key, typename Value, typename Map>
+ struct has_kv_in_map
+ : mpl::eval_if<
+ fusion::result_of::has_key<Map, Key>
+ , mpl::apply<
+ is_substitute<
+ fusion::result_of::value_at_key<mpl::_1, Key>
+ , Value>
+ , Map>
+ , mpl::false_>
+ {};
+
+ // if p_key is variant over multiple types (as a result of
+ // "(key1|key2|key3) >> p_value" parser) check that all
+ // keys are found in fusion::map attribute and that values
+ // under these keys match p_value
+ template <typename Variant>
+ struct variant_kv
+ : mpl::equal_to<
+ mpl::size< typename Variant::types>
+ , mpl::size< mpl::filter_view<typename Variant::types
+ , has_kv_in_map<mpl::_1, p_value, Attribute>>>
+ >
+ {};
+
+ typedef typename
+ mpl::eval_if<
+ is_variant<p_key>
+ , variant_kv<p_key>
+ , has_kv_in_map<p_key, p_value, Attribute>
+ >::type
+ type;
+ };
+
+ template <typename T, typename Attribute>
+ struct is_substitute<optional<T>, optional<Attribute>>
+ : is_substitute<T, Attribute> {};
+}}}}
+
+#endif