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