1 // Copyright (c) 2001-2011 Hartmut Kaiser 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See accompanying 4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 5 6 #if !defined(BOOST_SPIRIT_KARMA_EXTRACT_FROM_SEP_30_2009_0732AM) 7 #define BOOST_SPIRIT_KARMA_EXTRACT_FROM_SEP_30_2009_0732AM 8 9 #if defined(_MSC_VER) 10 #pragma once 11 #endif 12 13 #include <boost/spirit/include/phoenix_core.hpp> 14 #include <boost/spirit/home/support/unused.hpp> 15 #include <boost/spirit/home/support/attributes_fwd.hpp> 16 #include <boost/spirit/home/karma/detail/attributes.hpp> 17 #include <boost/spirit/home/support/container.hpp> 18 19 #include <boost/ref.hpp> 20 #include <boost/optional.hpp> 21 22 /////////////////////////////////////////////////////////////////////////////// 23 namespace boost { namespace spirit { namespace traits 24 { 25 /////////////////////////////////////////////////////////////////////////// 26 // This file contains attribute extraction utilities. The utilities 27 // provided also accept spirit's unused_type; all no-ops. Compiler 28 // optimization will easily strip these away. 29 /////////////////////////////////////////////////////////////////////////// 30 31 namespace detail 32 { 33 /////////////////////////////////////////////////////////////////////// 34 // extract first and second element of a fusion sequence 35 template <typename T> 36 struct add_const_ref 37 : add_reference<typename add_const<T>::type> 38 {}; 39 40 template <typename T, int N> 41 struct value_at_c 42 : add_const_ref<typename fusion::result_of::value_at_c<T, N>::type> 43 {}; 44 } 45 46 // This is the default case: the plain attribute values 47 template <typename Attribute, typename Exposed, typename Enable/*= void*/> 48 struct extract_from_attribute 49 { 50 typedef typename traits::one_element_sequence<Attribute>::type 51 is_one_element_sequence; 52 53 typedef typename mpl::eval_if< 54 is_one_element_sequence 55 , detail::value_at_c<Attribute, 0> 56 , mpl::identity<Attribute const&> 57 >::type type; 58 59 template <typename Context> callboost::spirit::traits::extract_from_attribute60 static type call(Attribute const& attr, Context&, mpl::false_) 61 { 62 return attr; 63 } 64 65 // This handles the case where the attribute is a single element fusion 66 // sequence. We silently extract the only element and treat it as the 67 // attribute to generate output from. 68 template <typename Context> callboost::spirit::traits::extract_from_attribute69 static type call(Attribute const& attr, Context& ctx, mpl::true_) 70 { 71 return extract_from<Exposed>(fusion::at_c<0>(attr), ctx); 72 } 73 74 template <typename Context> callboost::spirit::traits::extract_from_attribute75 static type call(Attribute const& attr, Context& ctx) 76 { 77 return call(attr, ctx, is_one_element_sequence()); 78 } 79 }; 80 81 // This handles optional attributes. 82 template <typename Attribute, typename Exposed> 83 struct extract_from_attribute<boost::optional<Attribute>, Exposed> 84 { 85 typedef Attribute const& type; 86 87 template <typename Context> callboost::spirit::traits::extract_from_attribute88 static type call(boost::optional<Attribute> const& attr, Context& ctx) 89 { 90 return extract_from<Exposed>(boost::get<Attribute>(attr), ctx); 91 } 92 }; 93 94 template <typename Attribute, typename Exposed> 95 struct extract_from_attribute<boost::optional<Attribute const>, Exposed> 96 { 97 typedef Attribute const& type; 98 99 template <typename Context> callboost::spirit::traits::extract_from_attribute100 static type call(boost::optional<Attribute const> const& attr, Context& ctx) 101 { 102 return extract_from<Exposed>(boost::get<Attribute const>(attr), ctx); 103 } 104 }; 105 106 // This handles attributes wrapped inside a boost::ref(). 107 template <typename Attribute, typename Exposed> 108 struct extract_from_attribute<reference_wrapper<Attribute>, Exposed> 109 { 110 typedef Attribute const& type; 111 112 template <typename Context> callboost::spirit::traits::extract_from_attribute113 static type call(reference_wrapper<Attribute> const& attr, Context& ctx) 114 { 115 return extract_from<Exposed>(attr.get(), ctx); 116 } 117 }; 118 119 /////////////////////////////////////////////////////////////////////////// 120 template <typename Attribute, typename Exposed, typename Enable> 121 struct extract_from_container 122 { 123 typedef typename traits::container_value<Attribute const>::type 124 value_type; 125 typedef typename is_convertible<value_type, Exposed>::type 126 is_convertible_to_value_type; 127 128 typedef typename mpl::if_< 129 mpl::or_< 130 is_same<value_type, Exposed>, is_same<Attribute, Exposed> > 131 , Exposed const&, Exposed 132 >::type type; 133 134 // handle case where container value type is convertible to result type 135 // we simply return the front element of the container 136 template <typename Context, typename Pred> callboost::spirit::traits::extract_from_container137 static type call(Attribute const& attr, Context&, mpl::true_, Pred) 138 { 139 // return first element from container 140 typedef typename traits::container_iterator<Attribute const>::type 141 iterator_type; 142 143 iterator_type it = traits::begin(attr); 144 type result = *it; 145 ++it; 146 return result; 147 } 148 149 // handle strings 150 template <typename Iterator> append_to_stringboost::spirit::traits::extract_from_container151 static void append_to_string(Exposed& result, Iterator begin, Iterator end) 152 { 153 for (Iterator i = begin; i != end; ++i) 154 push_back(result, *i); 155 } 156 157 template <typename Context> callboost::spirit::traits::extract_from_container158 static type call(Attribute const& attr, Context&, mpl::false_, mpl::true_) 159 { 160 typedef typename char_type_of<Attribute>::type char_type; 161 162 Exposed result; 163 append_to_string(result, traits::get_begin<char_type>(attr) 164 , traits::get_end<char_type>(attr)); 165 return result; 166 } 167 168 // everything else gets just passed through 169 template <typename Context> callboost::spirit::traits::extract_from_container170 static type call(Attribute const& attr, Context&, mpl::false_, mpl::false_) 171 { 172 return type(attr); 173 } 174 175 template <typename Context> callboost::spirit::traits::extract_from_container176 static type call(Attribute const& attr, Context& ctx) 177 { 178 typedef typename mpl::and_< 179 traits::is_string<Exposed>, traits::is_string<Attribute> 180 >::type handle_strings; 181 182 // return first element from container 183 return call(attr, ctx, is_convertible_to_value_type() 184 , handle_strings()); 185 } 186 }; 187 188 template <typename Attribute> 189 struct extract_from_container<Attribute, Attribute> 190 { 191 typedef Attribute const& type; 192 193 template <typename Context> callboost::spirit::traits::extract_from_container194 static type call(Attribute const& attr, Context&) 195 { 196 return attr; 197 } 198 }; 199 200 /////////////////////////////////////////////////////////////////////////// 201 namespace detail 202 { 203 // overload for non-container attributes 204 template <typename Exposed, typename Attribute, typename Context> 205 inline typename spirit::result_of::extract_from<Exposed, Attribute>::type extract_from(Attribute const & attr,Context & ctx,mpl::false_)206 extract_from(Attribute const& attr, Context& ctx, mpl::false_) 207 { 208 return extract_from_attribute<Attribute, Exposed>::call(attr, ctx); 209 } 210 211 // overload for containers (but not for variants or optionals 212 // holding containers) 213 template <typename Exposed, typename Attribute, typename Context> 214 inline typename spirit::result_of::extract_from<Exposed, Attribute>::type extract_from(Attribute const & attr,Context & ctx,mpl::true_)215 extract_from(Attribute const& attr, Context& ctx, mpl::true_) 216 { 217 return extract_from_container<Attribute, Exposed>::call(attr, ctx); 218 } 219 } 220 221 template <typename Exposed, typename Attribute, typename Context> 222 inline typename spirit::result_of::extract_from<Exposed, Attribute>::type extract_from(Attribute const & attr,Context & ctx,typename enable_if<traits::not_is_unused<Attribute>>::type *)223 extract_from(Attribute const& attr, Context& ctx 224 #if (defined(__GNUC__) && (__GNUC__ < 4)) || \ 225 (defined(__APPLE__) && defined(__INTEL_COMPILER)) 226 , typename enable_if<traits::not_is_unused<Attribute> >::type* 227 #endif 228 ) 229 { 230 typedef typename mpl::and_< 231 traits::is_container<Attribute> 232 , traits::not_is_variant<Attribute> 233 , traits::not_is_optional<Attribute> 234 >::type is_not_wrapped_container; 235 236 return detail::extract_from<Exposed>(attr, ctx 237 , is_not_wrapped_container()); 238 } 239 240 template <typename Exposed, typename Context> extract_from(unused_type,Context &)241 inline unused_type extract_from(unused_type, Context&) 242 { 243 return unused; 244 } 245 }}} 246 247 /////////////////////////////////////////////////////////////////////////////// 248 namespace boost { namespace spirit { namespace result_of 249 { 250 template <typename Exposed, typename Attribute> 251 struct extract_from 252 : mpl::if_< 253 mpl::and_< 254 traits::is_container<Attribute> 255 , traits::not_is_variant<Attribute> 256 , traits::not_is_optional<Attribute> > 257 , traits::extract_from_container<Attribute, Exposed> 258 , traits::extract_from_attribute<Attribute, Exposed> >::type 259 {}; 260 261 template <typename Exposed> 262 struct extract_from<Exposed, unused_type> 263 { 264 typedef unused_type type; 265 }; 266 267 template <typename Exposed> 268 struct extract_from<Exposed, unused_type const> 269 { 270 typedef unused_type type; 271 }; 272 }}} 273 274 #endif 275