diff options
Diffstat (limited to 'boost/spirit/home/x3/support/traits/is_substitute.hpp')
-rw-r--r-- | boost/spirit/home/x3/support/traits/is_substitute.hpp | 164 |
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 |