Chris@16: // Copyright (c) 2001-2011 Hartmut Kaiser Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #if !defined(BOOST_SPIRIT_KARMA_EXTRACT_FROM_SEP_30_2009_0732AM) Chris@16: #define BOOST_SPIRIT_KARMA_EXTRACT_FROM_SEP_30_2009_0732AM Chris@16: Chris@16: #if defined(_MSC_VER) Chris@16: #pragma once Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: namespace boost { namespace spirit { namespace traits Chris@16: { Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // This file contains attribute extraction utilities. The utilities Chris@16: // provided also accept spirit's unused_type; all no-ops. Compiler Chris@16: // optimization will easily strip these away. Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: /////////////////////////////////////////////////////////////////////// Chris@16: // extract first and second element of a fusion sequence Chris@16: template Chris@16: struct add_const_ref Chris@16: : add_reference::type> Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct value_at_c Chris@16: : add_const_ref::type> Chris@16: {}; Chris@16: } Chris@16: Chris@16: // This is the default case: the plain attribute values Chris@16: template Chris@16: struct extract_from_attribute Chris@16: { Chris@16: typedef typename traits::one_element_sequence::type Chris@16: is_one_element_sequence; Chris@16: Chris@16: typedef typename mpl::eval_if< Chris@16: is_one_element_sequence Chris@16: , detail::value_at_c Chris@16: , mpl::identity Chris@16: >::type type; Chris@16: Chris@16: template Chris@16: static type call(Attribute const& attr, Context&, mpl::false_) Chris@16: { Chris@16: return attr; Chris@16: } Chris@16: Chris@16: // This handles the case where the attribute is a single element fusion Chris@16: // sequence. We silently extract the only element and treat it as the Chris@16: // attribute to generate output from. Chris@16: template Chris@16: static type call(Attribute const& attr, Context& ctx, mpl::true_) Chris@16: { Chris@16: return extract_from(fusion::at_c<0>(attr), ctx); Chris@16: } Chris@16: Chris@16: template Chris@16: static type call(Attribute const& attr, Context& ctx) Chris@16: { Chris@16: return call(attr, ctx, is_one_element_sequence()); Chris@16: } Chris@16: }; Chris@16: Chris@16: // This handles optional attributes. Chris@16: template Chris@16: struct extract_from_attribute, Exposed> Chris@16: { Chris@16: typedef Attribute const& type; Chris@16: Chris@16: template Chris@16: static type call(boost::optional const& attr, Context& ctx) Chris@16: { Chris@16: return extract_from(boost::get(attr), ctx); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct extract_from_attribute, Exposed> Chris@16: { Chris@16: typedef Attribute const& type; Chris@16: Chris@16: template Chris@16: static type call(boost::optional const& attr, Context& ctx) Chris@16: { Chris@16: return extract_from(boost::get(attr), ctx); Chris@16: } Chris@16: }; Chris@16: Chris@16: // This handles attributes wrapped inside a boost::ref(). Chris@16: template Chris@16: struct extract_from_attribute, Exposed> Chris@16: { Chris@16: typedef Attribute const& type; Chris@16: Chris@16: template Chris@16: static type call(reference_wrapper const& attr, Context& ctx) Chris@16: { Chris@16: return extract_from(attr.get(), ctx); Chris@16: } Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct extract_from_container Chris@16: { Chris@16: typedef typename traits::container_value::type Chris@16: value_type; Chris@16: typedef typename is_convertible::type Chris@16: is_convertible_to_value_type; Chris@16: Chris@16: typedef typename mpl::if_< Chris@16: mpl::or_< Chris@16: is_same, is_same > Chris@16: , Exposed const&, Exposed Chris@16: >::type type; Chris@16: Chris@16: // handle case where container value type is convertible to result type Chris@16: // we simply return the front element of the container Chris@16: template Chris@16: static type call(Attribute const& attr, Context&, mpl::true_, Pred) Chris@16: { Chris@16: // return first element from container Chris@16: typedef typename traits::container_iterator::type Chris@16: iterator_type; Chris@16: Chris@16: iterator_type it = traits::begin(attr); Chris@16: type result = *it; Chris@16: ++it; Chris@16: return result; Chris@16: } Chris@16: Chris@16: // handle strings Chris@16: template Chris@16: static void append_to_string(Exposed& result, Iterator begin, Iterator end) Chris@16: { Chris@16: for (Iterator i = begin; i != end; ++i) Chris@16: push_back(result, *i); Chris@16: } Chris@16: Chris@16: template Chris@16: static type call(Attribute const& attr, Context&, mpl::false_, mpl::true_) Chris@16: { Chris@16: typedef typename char_type_of::type char_type; Chris@16: Chris@16: Exposed result; Chris@16: append_to_string(result, traits::get_begin(attr) Chris@16: , traits::get_end(attr)); Chris@16: return result; Chris@16: } Chris@16: Chris@16: // everything else gets just passed through Chris@16: template Chris@16: static type call(Attribute const& attr, Context&, mpl::false_, mpl::false_) Chris@16: { Chris@16: return type(attr); Chris@16: } Chris@16: Chris@16: template Chris@16: static type call(Attribute const& attr, Context& ctx) Chris@16: { Chris@16: typedef typename mpl::and_< Chris@16: traits::is_string, traits::is_string Chris@16: >::type handle_strings; Chris@16: Chris@16: // return first element from container Chris@16: return call(attr, ctx, is_convertible_to_value_type() Chris@16: , handle_strings()); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct extract_from_container Chris@16: { Chris@16: typedef Attribute const& type; Chris@16: Chris@16: template Chris@16: static type call(Attribute const& attr, Context&) Chris@16: { Chris@16: return attr; Chris@16: } Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: namespace detail Chris@16: { Chris@16: // overload for non-container attributes Chris@16: template Chris@16: inline typename spirit::result_of::extract_from::type Chris@16: extract_from(Attribute const& attr, Context& ctx, mpl::false_) Chris@16: { Chris@16: return extract_from_attribute::call(attr, ctx); Chris@16: } Chris@16: Chris@16: // overload for containers (but not for variants or optionals Chris@16: // holding containers) Chris@16: template Chris@16: inline typename spirit::result_of::extract_from::type Chris@16: extract_from(Attribute const& attr, Context& ctx, mpl::true_) Chris@16: { Chris@16: return extract_from_container::call(attr, ctx); Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: inline typename spirit::result_of::extract_from::type Chris@16: extract_from(Attribute const& attr, Context& ctx Chris@16: #if (defined(__GNUC__) && (__GNUC__ < 4)) || \ Chris@16: (defined(__APPLE__) && defined(__INTEL_COMPILER)) Chris@16: , typename enable_if >::type* Chris@16: #endif Chris@16: ) Chris@16: { Chris@16: typedef typename mpl::and_< Chris@16: traits::is_container Chris@16: , traits::not_is_variant Chris@16: , traits::not_is_optional Chris@16: >::type is_not_wrapped_container; Chris@16: Chris@16: return detail::extract_from(attr, ctx Chris@16: , is_not_wrapped_container()); Chris@16: } Chris@16: Chris@16: template Chris@16: inline unused_type extract_from(unused_type, Context&) Chris@16: { Chris@16: return unused; Chris@16: } Chris@16: }}} Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: namespace boost { namespace spirit { namespace result_of Chris@16: { Chris@16: template Chris@16: struct extract_from Chris@16: : mpl::if_< Chris@16: mpl::and_< Chris@16: traits::is_container Chris@16: , traits::not_is_variant Chris@16: , traits::not_is_optional > Chris@16: , traits::extract_from_container Chris@16: , traits::extract_from_attribute >::type Chris@16: {}; Chris@16: Chris@16: template Chris@16: struct extract_from Chris@16: { Chris@16: typedef unused_type type; Chris@16: }; Chris@16: Chris@16: template Chris@16: struct extract_from Chris@16: { Chris@16: typedef unused_type type; Chris@16: }; Chris@16: }}} Chris@16: Chris@16: #endif