1 // Copyright (c) 2001-2011 Hartmut Kaiser 2 // Copyright (c) 2001-2011 Joel de Guzman 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 7 #ifndef BOOST_SPIRIT_KARMA_DETAIL_ALTERNATIVE_FUNCTION_HPP 8 #define BOOST_SPIRIT_KARMA_DETAIL_ALTERNATIVE_FUNCTION_HPP 9 10 #if defined(_MSC_VER) 11 #pragma once 12 #endif 13 14 #include <boost/spirit/home/karma/domain.hpp> 15 #include <boost/spirit/home/karma/directive/buffer.hpp> 16 #include <boost/spirit/home/support/unused.hpp> 17 #include <boost/spirit/home/support/utree/utree_traits_fwd.hpp> 18 #include <boost/spirit/home/karma/detail/attributes.hpp> 19 #include <boost/spirit/home/support/detail/hold_any.hpp> 20 #include <boost/spirit/home/karma/detail/output_iterator.hpp> 21 #include <boost/spirit/home/support/container.hpp> 22 #include <boost/utility/enable_if.hpp> 23 #include <boost/variant.hpp> 24 #include <boost/detail/workaround.hpp> 25 26 /////////////////////////////////////////////////////////////////////////////// 27 namespace boost { namespace spirit { namespace karma { namespace detail 28 { 29 /////////////////////////////////////////////////////////////////////////// 30 // execute a generator if the given Attribute type is compatible 31 /////////////////////////////////////////////////////////////////////////// 32 33 // this gets instantiated if the Attribute type is _not_ compatible with 34 // the generator 35 template <typename Component, typename Attribute, typename Expected 36 , typename Enable = void> 37 struct alternative_generate 38 { 39 template <typename OutputIterator, typename Context, typename Delimiter> 40 static bool callboost::spirit::karma::detail::alternative_generate41 call(Component const&, OutputIterator&, Context&, Delimiter const& 42 , Attribute const&, bool& failed) 43 { 44 failed = true; 45 return false; 46 } 47 }; 48 49 template <typename Component> 50 struct alternative_generate<Component, unused_type, unused_type> 51 { 52 template <typename OutputIterator, typename Context, typename Delimiter> 53 static bool callboost::spirit::karma::detail::alternative_generate54 call(Component const& component, OutputIterator& sink, Context& ctx 55 , Delimiter const& d, unused_type, bool&) 56 { 57 #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) 58 component; // suppresses warning: C4100: 'component' : unreferenced formal parameter 59 #endif 60 // return true if any of the generators succeed 61 return component.generate(sink, ctx, d, unused); 62 } 63 }; 64 65 // this gets instantiated if there is no Attribute given for the 66 // alternative generator 67 template <typename Component, typename Expected> 68 struct alternative_generate<Component, unused_type, Expected> 69 : alternative_generate<Component, unused_type, unused_type> {}; 70 71 // this gets instantiated if the generator does not expect to receive an 72 // Attribute (the generator is self contained). 73 template <typename Component, typename Attribute> 74 struct alternative_generate<Component, Attribute, unused_type> 75 : alternative_generate<Component, unused_type, unused_type> {}; 76 77 // this gets instantiated if the Attribute type is compatible to the 78 // generator 79 template <typename Component, typename Attribute, typename Expected> 80 struct alternative_generate<Component, Attribute, Expected 81 , typename enable_if< 82 traits::compute_compatible_component<Expected, Attribute, karma::domain> >::type> 83 { 84 template <typename OutputIterator, typename Context, typename Delimiter> 85 static bool callboost::spirit::karma::detail::alternative_generate86 call(Component const& component, OutputIterator& sink 87 , Context& ctx, Delimiter const& d, Attribute const& attr, bool&) 88 { 89 #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) 90 component; // suppresses warning: C4100: 'component' : unreferenced formal parameter 91 #endif 92 return call(component, sink, ctx, d, attr 93 , spirit::traits::not_is_variant_or_variant_in_optional<Attribute, karma::domain>()); 94 } 95 96 template <typename OutputIterator, typename Context, typename Delimiter> 97 static bool callboost::spirit::karma::detail::alternative_generate98 call(Component const& component, OutputIterator& sink 99 , Context& ctx, Delimiter const& d, Attribute const& attr, mpl::true_) 100 { 101 #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) 102 component; // suppresses warning: C4100: 'component' : unreferenced formal parameter 103 #endif 104 return component.generate(sink, ctx, d, attr); 105 } 106 107 template <typename OutputIterator, typename Context, typename Delimiter> 108 static bool callboost::spirit::karma::detail::alternative_generate109 call(Component const& component, OutputIterator& sink 110 , Context& ctx, Delimiter const& d, Attribute const& attr, mpl::false_) 111 { 112 #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) 113 component; // suppresses warning: C4100: 'component' : unreferenced formal parameter 114 #endif 115 typedef 116 traits::compute_compatible_component<Expected, Attribute, domain> 117 component_type; 118 119 // if we got passed an empty optional, just fail generation 120 if (!traits::has_optional_value(attr)) 121 return false; 122 123 // make sure, the content of the passed variant matches our 124 // expectations 125 typename traits::optional_attribute<Attribute>::type attr_ = 126 traits::optional_value(attr); 127 if (!component_type::is_compatible(spirit::traits::which(attr_))) 128 return false; 129 130 // returns true if any of the generators succeed 131 typedef typename component_type::compatible_type compatible_type; 132 return component.generate(sink, ctx, d 133 , boost::get<compatible_type>(attr_)); 134 } 135 }; 136 137 /////////////////////////////////////////////////////////////////////////// 138 // alternative_generate_function: a functor supplied to fusion::any which 139 // will be executed for every generator in a given alternative generator 140 // expression 141 /////////////////////////////////////////////////////////////////////////// 142 template <typename OutputIterator, typename Context, typename Delimiter, 143 typename Attribute, typename Strict> 144 struct alternative_generate_function 145 { alternative_generate_functionboost::spirit::karma::detail::alternative_generate_function146 alternative_generate_function(OutputIterator& sink_, Context& ctx_ 147 , Delimiter const& d, Attribute const& attr_) 148 : sink(sink_), ctx(ctx_), delim(d), attr(attr_) {} 149 150 template <typename Component> operator ()boost::spirit::karma::detail::alternative_generate_function151 bool operator()(Component const& component) 152 { 153 typedef 154 typename traits::attribute_of<Component, Context>::type 155 expected_type; 156 typedef 157 alternative_generate<Component, Attribute, expected_type> 158 generate; 159 160 // wrap the given output iterator avoid output as long as one 161 // component fails 162 detail::enable_buffering<OutputIterator> buffering(sink); 163 bool r = false; 164 bool failed = false; // will be ignored 165 { 166 detail::disable_counting<OutputIterator> nocounting(sink); 167 r = generate::call(component, sink, ctx, delim, attr, failed); 168 } 169 if (r) 170 buffering.buffer_copy(); 171 return r; 172 } 173 174 // avoid double buffering 175 template <typename Component> operator ()boost::spirit::karma::detail::alternative_generate_function176 bool operator()(buffer_directive<Component> const& component) 177 { 178 typedef typename 179 traits::attribute_of<Component, Context>::type 180 expected_type; 181 typedef alternative_generate< 182 buffer_directive<Component>, Attribute, expected_type> 183 generate; 184 185 bool failed = false; // will be ignored 186 return generate::call(component, sink, ctx, delim, attr, failed); 187 } 188 189 OutputIterator& sink; 190 Context& ctx; 191 Delimiter const& delim; 192 Attribute const& attr; 193 194 // silence MSVC warning C4512: assignment operator could not be generated 195 BOOST_DELETED_FUNCTION(alternative_generate_function& operator= (alternative_generate_function const&)) 196 }; 197 198 // specialization for strict alternatives 199 template <typename OutputIterator, typename Context, typename Delimiter, 200 typename Attribute> 201 struct alternative_generate_function< 202 OutputIterator, Context, Delimiter, Attribute, mpl::true_> 203 { alternative_generate_functionboost::spirit::karma::detail::alternative_generate_function204 alternative_generate_function(OutputIterator& sink_, Context& ctx_ 205 , Delimiter const& d, Attribute const& attr_) 206 : sink(sink_), ctx(ctx_), delim(d), attr(attr_), failed(false) {} 207 208 template <typename Component> operator ()boost::spirit::karma::detail::alternative_generate_function209 bool operator()(Component const& component) 210 { 211 typedef 212 typename traits::attribute_of<Component, Context>::type 213 expected_type; 214 typedef 215 alternative_generate<Component, Attribute, expected_type> 216 generate; 217 218 if (failed) 219 return false; // give up when already failed 220 221 // wrap the given output iterator avoid output as long as one 222 // component fails 223 detail::enable_buffering<OutputIterator> buffering(sink); 224 bool r = false; 225 { 226 detail::disable_counting<OutputIterator> nocounting(sink); 227 r = generate::call(component, sink, ctx, delim, attr, failed); 228 } 229 if (r && !failed) 230 { 231 buffering.buffer_copy(); 232 return true; 233 } 234 return false; 235 } 236 237 OutputIterator& sink; 238 Context& ctx; 239 Delimiter const& delim; 240 Attribute const& attr; 241 bool failed; 242 243 // silence MSVC warning C4512: assignment operator could not be generated 244 BOOST_DELETED_FUNCTION(alternative_generate_function& operator= (alternative_generate_function const&)) 245 }; 246 }}}} 247 248 #endif 249