1 /*============================================================================= 2 Copyright (c) 2001-2011 Joel de Guzman 3 Copyright (c) 2001-2011 Hartmut Kaiser 4 http://spirit.sourceforge.net/ 5 6 Distributed under the Boost Software License, Version 1.0. (See accompanying 7 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 8 =============================================================================*/ 9 #if !defined(BOOST_SPIRIT_ASSIGN_TO_APR_16_2006_0812PM) 10 #define BOOST_SPIRIT_ASSIGN_TO_APR_16_2006_0812PM 11 12 #if defined(_MSC_VER) 13 #pragma once 14 #endif 15 16 #include <boost/spirit/home/qi/detail/construct.hpp> 17 #include <boost/spirit/home/support/unused.hpp> 18 #include <boost/spirit/home/qi/detail/attributes.hpp> 19 #include <boost/spirit/home/support/container.hpp> 20 #include <boost/fusion/include/copy.hpp> 21 #include <boost/fusion/adapted/struct/detail/extension.hpp> 22 #include <boost/ref.hpp> 23 #include <boost/range/range_fwd.hpp> 24 25 namespace boost { namespace spirit { namespace traits 26 { 27 /////////////////////////////////////////////////////////////////////////// 28 // This file contains assignment utilities. The utilities provided also 29 // accept spirit's unused_type; all no-ops. Compiler optimization will 30 // easily strip these away. 31 /////////////////////////////////////////////////////////////////////////// 32 namespace detail 33 { 34 template <typename T> 35 struct is_iter_range : mpl::false_ {}; 36 37 template <typename I> 38 struct is_iter_range<boost::iterator_range<I> > : mpl::true_ {}; 39 40 template <typename C> 41 struct is_container_of_ranges 42 : is_iter_range<typename C::value_type> {}; 43 } 44 45 template <typename Attribute, typename Iterator, typename Enable> 46 struct assign_to_attribute_from_iterators 47 { 48 // Common case 49 static void callboost::spirit::traits::assign_to_attribute_from_iterators50 call(Iterator const& first, Iterator const& last, Attribute& attr, mpl::false_) 51 { 52 if (traits::is_empty(attr)) 53 attr = Attribute(first, last); 54 else { 55 for (Iterator i = first; i != last; ++i) 56 push_back(attr, *i); 57 } 58 } 59 60 // If Attribute is a container with value_type==iterator_range<T> just push the 61 // iterator_range into it 62 static void callboost::spirit::traits::assign_to_attribute_from_iterators63 call(Iterator const& first, Iterator const& last, Attribute& attr, mpl::true_) 64 { 65 typename Attribute::value_type rng(first, last); 66 push_back(attr, rng); 67 } 68 69 static void callboost::spirit::traits::assign_to_attribute_from_iterators70 call(Iterator const& first, Iterator const& last, Attribute& attr) 71 { 72 call(first, last, attr, detail::is_container_of_ranges<Attribute>()); 73 } 74 }; 75 76 template <typename Attribute, typename Iterator> 77 struct assign_to_attribute_from_iterators< 78 reference_wrapper<Attribute>, Iterator> 79 { 80 static void callboost::spirit::traits::assign_to_attribute_from_iterators81 call(Iterator const& first, Iterator const& last 82 , reference_wrapper<Attribute> attr) 83 { 84 if (traits::is_empty(attr)) 85 attr = Attribute(first, last); 86 else { 87 for (Iterator i = first; i != last; ++i) 88 push_back(attr, *i); 89 } 90 } 91 }; 92 93 template <typename Attribute, typename Iterator> 94 struct assign_to_attribute_from_iterators< 95 boost::optional<Attribute>, Iterator> 96 { 97 static void callboost::spirit::traits::assign_to_attribute_from_iterators98 call(Iterator const& first, Iterator const& last 99 , boost::optional<Attribute>& attr) 100 { 101 Attribute val; 102 assign_to(first, last, val); 103 attr = val; 104 } 105 }; 106 107 template <typename Iterator> 108 struct assign_to_attribute_from_iterators< 109 iterator_range<Iterator>, Iterator> 110 { 111 static void callboost::spirit::traits::assign_to_attribute_from_iterators112 call(Iterator const& first, Iterator const& last 113 , iterator_range<Iterator>& attr) 114 { 115 attr = iterator_range<Iterator>(first, last); 116 } 117 }; 118 119 template <typename Iterator, typename Attribute> 120 inline void assign_to(Iterator const & first,Iterator const & last,Attribute & attr)121 assign_to(Iterator const& first, Iterator const& last, Attribute& attr) 122 { 123 assign_to_attribute_from_iterators<Attribute, Iterator>:: 124 call(first, last, attr); 125 } 126 127 template <typename Iterator> 128 inline void assign_to(Iterator const &,Iterator const &,unused_type)129 assign_to(Iterator const&, Iterator const&, unused_type) 130 { 131 } 132 133 /////////////////////////////////////////////////////////////////////////// 134 template <typename T, typename Attribute> 135 void assign_to(T const& val, Attribute& attr); 136 137 template <typename Attribute, typename T, typename Enable> 138 struct assign_to_attribute_from_value 139 { 140 typedef typename traits::one_element_sequence<Attribute>::type 141 is_one_element_sequence; 142 143 typedef typename mpl::eval_if< 144 is_one_element_sequence 145 , fusion::result_of::at_c<Attribute, 0> 146 , mpl::identity<Attribute&> 147 >::type type; 148 149 template <typename T_> 150 static void callboost::spirit::traits::assign_to_attribute_from_value151 call(T_ const& val, Attribute& attr, mpl::false_) 152 { 153 attr = static_cast<Attribute>(val); 154 } 155 156 // This handles the case where the attribute is a single element fusion 157 // sequence. We silently assign to the only element and treat it as the 158 // attribute to parse the results into. 159 template <typename T_> 160 static void callboost::spirit::traits::assign_to_attribute_from_value161 call(T_ const& val, Attribute& attr, mpl::true_) 162 { 163 typedef typename fusion::result_of::value_at_c<Attribute, 0>::type 164 element_type; 165 fusion::at_c<0>(attr) = static_cast<element_type>(val); 166 } 167 168 static void callboost::spirit::traits::assign_to_attribute_from_value169 call(T const& val, Attribute& attr) 170 { 171 call(val, attr, is_one_element_sequence()); 172 } 173 }; 174 175 template <typename Attribute> 176 struct assign_to_attribute_from_value<Attribute, Attribute> 177 { 178 static void callboost::spirit::traits::assign_to_attribute_from_value179 call(Attribute const& val, Attribute& attr) 180 { 181 attr = val; 182 } 183 }; 184 185 template <typename Attribute, typename T> 186 struct assign_to_attribute_from_value<Attribute, reference_wrapper<T> 187 , typename disable_if<is_same<Attribute, reference_wrapper<T> > >::type> 188 { 189 static void callboost::spirit::traits::assign_to_attribute_from_value190 call(reference_wrapper<T> const& val, Attribute& attr) 191 { 192 assign_to(val.get(), attr); 193 } 194 }; 195 196 template <typename Attribute, typename T> 197 struct assign_to_attribute_from_value<Attribute, boost::optional<T> 198 , typename disable_if<is_same<Attribute, boost::optional<T> > >::type> 199 { 200 static void callboost::spirit::traits::assign_to_attribute_from_value201 call(boost::optional<T> const& val, Attribute& attr) 202 { 203 assign_to(val.get(), attr); 204 } 205 }; 206 207 template <typename Attribute, int N, bool Const, typename T> 208 struct assign_to_attribute_from_value<fusion::extension::adt_attribute_proxy<Attribute, N, Const>, T> 209 { 210 static void callboost::spirit::traits::assign_to_attribute_from_value211 call(T const& val, typename fusion::extension::adt_attribute_proxy<Attribute, N, Const>& attr) 212 { 213 attr = val; 214 } 215 }; 216 217 namespace detail 218 { 219 template <typename A, typename B> 220 struct is_same_size_sequence 221 : mpl::bool_<fusion::result_of::size<A>::value 222 == fusion::result_of::size<B>::value> 223 {}; 224 } 225 226 template <typename Attribute, typename T> 227 struct assign_to_attribute_from_value<Attribute, T, 228 mpl::and_< 229 fusion::traits::is_sequence<Attribute>, 230 fusion::traits::is_sequence<T>, 231 detail::is_same_size_sequence<Attribute, T> 232 > 233 > 234 { 235 static void callboost::spirit::traits::assign_to_attribute_from_value236 call(T const& val, Attribute& attr) 237 { 238 fusion::copy(val, attr); 239 } 240 }; 241 242 /////////////////////////////////////////////////////////////////////////// 243 template <typename Attribute, typename T, typename Enable> 244 struct assign_to_container_from_value 245 { 246 // T is not a container and not a string 247 template <typename T_> callboost::spirit::traits::assign_to_container_from_value248 static void call(T_ const& val, Attribute& attr, mpl::false_, mpl::false_) 249 { 250 traits::push_back(attr, val); 251 } 252 253 // T is a container (but not a string), and T is convertible to the 254 // value_type of the Attribute container 255 template <typename T_> 256 static void append_to_container_not_stringboost::spirit::traits::assign_to_container_from_value257 append_to_container_not_string(T_ const& val, Attribute& attr, mpl::true_) 258 { 259 traits::push_back(attr, val); 260 } 261 262 // T is a container (but not a string), generic overload 263 template <typename T_> 264 static void append_to_container_not_stringboost::spirit::traits::assign_to_container_from_value265 append_to_container_not_string(T_ const& val, Attribute& attr, mpl::false_) 266 { 267 typedef typename traits::container_iterator<T_ const>::type 268 iterator_type; 269 270 iterator_type end = traits::end(val); 271 for (iterator_type i = traits::begin(val); i != end; traits::next(i)) 272 traits::push_back(attr, traits::deref(i)); 273 } 274 275 // T is a container (but not a string) 276 template <typename T_> callboost::spirit::traits::assign_to_container_from_value277 static void call(T_ const& val, Attribute& attr, mpl::true_, mpl::false_) 278 { 279 typedef typename container_value<Attribute>::type value_type; 280 typedef typename is_convertible<T, value_type>::type is_value_type; 281 282 append_to_container_not_string(val, attr, is_value_type()); 283 } 284 285 /////////////////////////////////////////////////////////////////////// 286 // T is a string 287 template <typename Iterator> append_to_stringboost::spirit::traits::assign_to_container_from_value288 static void append_to_string(Attribute& attr, Iterator begin, Iterator end) 289 { 290 for (Iterator i = begin; i != end; ++i) 291 traits::push_back(attr, *i); 292 } 293 294 // T is string, but not convertible to value_type of container 295 template <typename T_> append_to_containerboost::spirit::traits::assign_to_container_from_value296 static void append_to_container(T_ const& val, Attribute& attr, mpl::false_) 297 { 298 typedef typename char_type_of<T_>::type char_type; 299 300 append_to_string(attr, traits::get_begin<char_type>(val) 301 , traits::get_end<char_type>(val)); 302 } 303 304 // T is string, and convertible to value_type of container 305 template <typename T_> append_to_containerboost::spirit::traits::assign_to_container_from_value306 static void append_to_container(T_ const& val, Attribute& attr, mpl::true_) 307 { 308 traits::push_back(attr, val); 309 } 310 311 template <typename T_, typename Pred> callboost::spirit::traits::assign_to_container_from_value312 static void call(T_ const& val, Attribute& attr, Pred, mpl::true_) 313 { 314 typedef typename container_value<Attribute>::type value_type; 315 typedef typename is_convertible<T, value_type>::type is_value_type; 316 317 append_to_container(val, attr, is_value_type()); 318 } 319 320 /////////////////////////////////////////////////////////////////////// callboost::spirit::traits::assign_to_container_from_value321 static void call(T const& val, Attribute& attr) 322 { 323 typedef typename traits::is_container<T>::type is_container; 324 typedef typename traits::is_string<T>::type is_string; 325 326 call(val, attr, is_container(), is_string()); 327 } 328 }; 329 330 template <typename Attribute> 331 struct assign_to_container_from_value<Attribute, Attribute> 332 { 333 static void callboost::spirit::traits::assign_to_container_from_value334 call(Attribute const& val, Attribute& attr) 335 { 336 attr = val; 337 } 338 }; 339 340 template <typename Attribute, typename T> 341 struct assign_to_container_from_value<Attribute, boost::optional<T> 342 , typename disable_if<is_same<Attribute, boost::optional<T> > >::type> 343 { 344 static void callboost::spirit::traits::assign_to_container_from_value345 call(boost::optional<T> const& val, Attribute& attr) 346 { 347 assign_to(val.get(), attr); 348 } 349 }; 350 351 template <typename Attribute, typename T> 352 struct assign_to_container_from_value<Attribute, reference_wrapper<T> 353 , typename disable_if<is_same<Attribute, reference_wrapper<T> > >::type> 354 { 355 static void callboost::spirit::traits::assign_to_container_from_value356 call(reference_wrapper<T> const& val, Attribute& attr) 357 { 358 assign_to(val.get(), attr); 359 } 360 }; 361 362 /////////////////////////////////////////////////////////////////////////// 363 namespace detail 364 { 365 // overload for non-container attributes 366 template <typename T, typename Attribute> 367 inline void assign_to(T const & val,Attribute & attr,mpl::false_)368 assign_to(T const& val, Attribute& attr, mpl::false_) 369 { 370 assign_to_attribute_from_value<Attribute, T>::call(val, attr); 371 } 372 373 // overload for containers (but not for variants or optionals 374 // holding containers) 375 template <typename T, typename Attribute> 376 inline void assign_to(T const & val,Attribute & attr,mpl::true_)377 assign_to(T const& val, Attribute& attr, mpl::true_) 378 { 379 assign_to_container_from_value<Attribute, T>::call(val, attr); 380 } 381 } 382 383 template <typename T, typename Attribute> 384 inline void assign_to(T const & val,Attribute & attr)385 assign_to(T const& val, Attribute& attr) 386 { 387 typedef typename mpl::and_< 388 traits::is_container<Attribute> 389 , traits::not_is_variant<Attribute> 390 , traits::not_is_optional<Attribute> 391 >::type is_not_wrapped_container; 392 393 detail::assign_to(val, attr, is_not_wrapped_container()); 394 } 395 396 template <typename T> 397 inline void assign_to(T const &,unused_type)398 assign_to(T const&, unused_type) 399 { 400 } 401 }}} 402 403 #endif 404