Chris@16: // Copyright (c) 2001-2011 Hartmut Kaiser Chris@16: // Copyright (c) 2001-2011 Joel de Guzman 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(SPIRIT_KARMA_ALTERNATIVE_MAR_01_2007_1124AM) Chris@16: #define SPIRIT_KARMA_ALTERNATIVE_MAR_01_2007_1124AM 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: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: namespace boost { namespace spirit { namespace karma { namespace detail Chris@16: { Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // execute a generator if the given Attribute type is compatible Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: Chris@16: // this gets instantiated if the Attribute type is _not_ compatible with Chris@16: // the generator Chris@16: template Chris@16: struct alternative_generate Chris@16: { Chris@16: template Chris@16: static bool Chris@16: call(Component const&, OutputIterator&, Context&, Delimiter const& Chris@16: , Attribute const&, bool& failed) Chris@16: { Chris@16: failed = true; Chris@16: return false; Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct alternative_generate Chris@16: { Chris@16: template Chris@16: static bool Chris@16: call(Component const& component, OutputIterator& sink, Context& ctx Chris@16: , Delimiter const& d, unused_type, bool&) Chris@16: { Chris@16: #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) Chris@16: component; // suppresses warning: C4100: 'component' : unreferenced formal parameter Chris@16: #endif Chris@16: // return true if any of the generators succeed Chris@16: return component.generate(sink, ctx, d, unused); Chris@16: } Chris@16: }; Chris@16: Chris@16: // this gets instantiated if there is no Attribute given for the Chris@16: // alternative generator Chris@16: template Chris@16: struct alternative_generate Chris@16: : alternative_generate {}; Chris@16: Chris@16: // this gets instantiated if the generator does not expect to receive an Chris@16: // Attribute (the generator is self contained). Chris@16: template Chris@16: struct alternative_generate Chris@16: : alternative_generate {}; Chris@16: Chris@16: // this gets instantiated if the Attribute type is compatible to the Chris@16: // generator Chris@16: template Chris@16: struct alternative_generate >::type> Chris@16: { Chris@16: template Chris@16: static bool Chris@16: call(Component const& component, OutputIterator& sink Chris@16: , Context& ctx, Delimiter const& d, Attribute const& attr, bool&) Chris@16: { Chris@16: #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) Chris@16: component; // suppresses warning: C4100: 'component' : unreferenced formal parameter Chris@16: #endif Chris@16: return call(component, sink, ctx, d, attr Chris@16: , spirit::traits::not_is_variant()); Chris@16: } Chris@16: Chris@16: template Chris@16: static bool Chris@16: call(Component const& component, OutputIterator& sink Chris@16: , Context& ctx, Delimiter const& d, Attribute const& attr, mpl::true_) Chris@16: { Chris@16: #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) Chris@16: component; // suppresses warning: C4100: 'component' : unreferenced formal parameter Chris@16: #endif Chris@16: return component.generate(sink, ctx, d, attr); Chris@16: } Chris@16: Chris@16: template Chris@16: static bool Chris@16: call(Component const& component, OutputIterator& sink Chris@16: , Context& ctx, Delimiter const& d, Attribute const& attr, mpl::false_) Chris@16: { Chris@16: #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) Chris@16: component; // suppresses warning: C4100: 'component' : unreferenced formal parameter Chris@16: #endif Chris@16: typedef Chris@16: traits::compute_compatible_component Chris@16: component_type; Chris@16: Chris@16: // if we got passed an empty optional, just fail generation Chris@16: if (!traits::has_optional_value(attr)) Chris@16: return false; Chris@16: Chris@16: // make sure, the content of the passed variant matches our Chris@16: // expectations Chris@16: typename traits::optional_attribute::type attr_ = Chris@16: traits::optional_value(attr); Chris@16: if (!component_type::is_compatible(spirit::traits::which(attr_))) Chris@16: return false; Chris@16: Chris@16: // returns true if any of the generators succeed Chris@16: typedef typename component_type::compatible_type compatible_type; Chris@16: return component.generate(sink, ctx, d Chris@16: , boost::get(attr_)); Chris@16: } Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: // alternative_generate_function: a functor supplied to fusion::any which Chris@16: // will be executed for every generator in a given alternative generator Chris@16: // expression Chris@16: /////////////////////////////////////////////////////////////////////////// Chris@16: template Chris@16: struct alternative_generate_function Chris@16: { Chris@16: alternative_generate_function(OutputIterator& sink_, Context& ctx_ Chris@16: , Delimiter const& d, Attribute const& attr_) Chris@16: : sink(sink_), ctx(ctx_), delim(d), attr(attr_) {} Chris@16: Chris@16: template Chris@16: bool operator()(Component const& component) Chris@16: { Chris@16: typedef Chris@16: typename traits::attribute_of::type Chris@16: expected_type; Chris@16: typedef Chris@16: alternative_generate Chris@16: generate; Chris@16: Chris@16: // wrap the given output iterator avoid output as long as one Chris@16: // component fails Chris@16: detail::enable_buffering buffering(sink); Chris@16: bool r = false; Chris@16: bool failed = false; // will be ignored Chris@16: { Chris@16: detail::disable_counting nocounting(sink); Chris@16: r = generate::call(component, sink, ctx, delim, attr, failed); Chris@16: } Chris@16: if (r) Chris@16: buffering.buffer_copy(); Chris@16: return r; Chris@16: } Chris@16: Chris@16: // avoid double buffering Chris@16: template Chris@16: bool operator()(buffer_directive const& component) Chris@16: { Chris@16: typedef typename Chris@16: traits::attribute_of::type Chris@16: expected_type; Chris@16: typedef alternative_generate< Chris@16: buffer_directive, Attribute, expected_type> Chris@16: generate; Chris@16: Chris@16: bool failed = false; // will be ignored Chris@16: return generate::call(component, sink, ctx, delim, attr, failed); Chris@16: } Chris@16: Chris@16: OutputIterator& sink; Chris@16: Context& ctx; Chris@16: Delimiter const& delim; Chris@16: Attribute const& attr; Chris@16: Chris@16: private: Chris@16: // silence MSVC warning C4512: assignment operator could not be generated Chris@16: alternative_generate_function& operator= (alternative_generate_function const&); Chris@16: }; Chris@16: Chris@16: // specialization for strict alternatives Chris@16: template Chris@16: struct alternative_generate_function< Chris@16: OutputIterator, Context, Delimiter, Attribute, mpl::true_> Chris@16: { Chris@16: alternative_generate_function(OutputIterator& sink_, Context& ctx_ Chris@16: , Delimiter const& d, Attribute const& attr_) Chris@16: : sink(sink_), ctx(ctx_), delim(d), attr(attr_), failed(false) {} Chris@16: Chris@16: template Chris@16: bool operator()(Component const& component) Chris@16: { Chris@16: typedef Chris@16: typename traits::attribute_of::type Chris@16: expected_type; Chris@16: typedef Chris@16: alternative_generate Chris@16: generate; Chris@16: Chris@16: if (failed) Chris@16: return false; // give up when already failed Chris@16: Chris@16: // wrap the given output iterator avoid output as long as one Chris@16: // component fails Chris@16: detail::enable_buffering buffering(sink); Chris@16: bool r = false; Chris@16: { Chris@16: detail::disable_counting nocounting(sink); Chris@16: r = generate::call(component, sink, ctx, delim, attr, failed); Chris@16: } Chris@16: if (r && !failed) Chris@16: { Chris@16: buffering.buffer_copy(); Chris@16: return true; Chris@16: } Chris@16: return false; Chris@16: } Chris@16: Chris@16: OutputIterator& sink; Chris@16: Context& ctx; Chris@16: Delimiter const& delim; Chris@16: Attribute const& attr; Chris@16: bool failed; Chris@16: Chris@16: private: Chris@16: // silence MSVC warning C4512: assignment operator could not be generated Chris@16: alternative_generate_function& operator= (alternative_generate_function const&); Chris@16: }; Chris@16: }}}} Chris@16: Chris@16: #endif