| // Copyright (c) 2001-2010 Hartmut Kaiser |
| // Copyright (c) 2001-2010 Joel de Guzman |
| // |
| // Distributed under the Boost Software License, Version 1.0. (See accompanying |
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| |
| #if !defined(SPIRIT_KARMA_ALTERNATIVE_MAR_01_2007_1124AM) |
| #define SPIRIT_KARMA_ALTERNATIVE_MAR_01_2007_1124AM |
| |
| #if defined(_MSC_VER) |
| #pragma once |
| #endif |
| |
| #include <boost/spirit/home/karma/domain.hpp> |
| #include <boost/spirit/home/karma/directive/buffer.hpp> |
| #include <boost/spirit/home/support/unused.hpp> |
| #include <boost/spirit/home/karma/detail/attributes.hpp> |
| #include <boost/spirit/home/support/detail/hold_any.hpp> |
| #include <boost/spirit/home/karma/detail/output_iterator.hpp> |
| #include <boost/spirit/home/support/container.hpp> |
| #include <boost/utility/enable_if.hpp> |
| #include <boost/variant.hpp> |
| #include <boost/detail/workaround.hpp> |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| namespace boost { namespace spirit { namespace karma { namespace detail |
| { |
| /////////////////////////////////////////////////////////////////////////// |
| // execute a generator if the given Attribute type is compatible |
| /////////////////////////////////////////////////////////////////////////// |
| |
| // this gets instantiated if the Attribute type is _not_ compatible with |
| // the generator |
| template <typename Component, typename Attribute, typename Expected |
| , typename Enable = void> |
| struct alternative_generate |
| { |
| template <typename OutputIterator, typename Context, typename Delimiter> |
| static bool |
| call(Component const&, OutputIterator&, Context&, Delimiter const& |
| , Attribute const&, bool& failed) |
| { |
| failed = true; |
| return false; |
| } |
| }; |
| |
| template <typename Component> |
| struct alternative_generate<Component, unused_type, unused_type> |
| { |
| template <typename OutputIterator, typename Context, typename Delimiter> |
| static bool |
| call(Component const& component, OutputIterator& sink, Context& ctx |
| , Delimiter const& d, unused_type, bool&) |
| { |
| #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) |
| component; // suppresses warning: C4100: 'component' : unreferenced formal parameter |
| #endif |
| // return true if any of the generators succeed |
| return component.generate(sink, ctx, d, unused); |
| } |
| }; |
| |
| // this gets instantiated if there is no Attribute given for the |
| // alternative generator |
| template <typename Component, typename Expected> |
| struct alternative_generate<Component, unused_type, Expected> |
| : alternative_generate<Component, unused_type, unused_type> {}; |
| |
| // this gets instantiated if the generator does not expect to receive an |
| // Attribute (the generator is self contained). |
| template <typename Component, typename Attribute> |
| struct alternative_generate<Component, Attribute, unused_type> |
| : alternative_generate<Component, unused_type, unused_type> {}; |
| |
| // this gets instantiated if the Attribute type is compatible to the |
| // generator |
| template <typename Component, typename Attribute, typename Expected> |
| struct alternative_generate<Component, Attribute, Expected |
| , typename enable_if< |
| traits::compute_compatible_component<Expected, Attribute, karma::domain> >::type> |
| { |
| template <typename OutputIterator, typename Context, typename Delimiter> |
| static bool |
| call(Component const& component, OutputIterator& sink |
| , Context& ctx, Delimiter const& d, Attribute const& attr, bool&) |
| { |
| #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) |
| component; // suppresses warning: C4100: 'component' : unreferenced formal parameter |
| #endif |
| return call(component, sink, ctx, d, attr |
| , spirit::traits::not_is_variant<Attribute, karma::domain>()); |
| } |
| |
| template <typename OutputIterator, typename Context, typename Delimiter> |
| static bool |
| call(Component const& component, OutputIterator& sink |
| , Context& ctx, Delimiter const& d, Attribute const& attr, mpl::true_) |
| { |
| #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) |
| component; // suppresses warning: C4100: 'component' : unreferenced formal parameter |
| #endif |
| return component.generate(sink, ctx, d, attr); |
| } |
| |
| template <typename OutputIterator, typename Context, typename Delimiter> |
| static bool |
| call(Component const& component, OutputIterator& sink |
| , Context& ctx, Delimiter const& d, Attribute const& attr, mpl::false_) |
| { |
| #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) |
| component; // suppresses warning: C4100: 'component' : unreferenced formal parameter |
| #endif |
| typedef |
| traits::compute_compatible_component<Expected, Attribute, domain> |
| component_type; |
| |
| // if we got passed an empty optional, just fail generation |
| if (!traits::has_optional_value(attr)) |
| return false; |
| |
| // make sure, the content of the passed variant matches our |
| // expectations |
| typename traits::optional_attribute<Attribute>::type attr_ = |
| traits::optional_value(attr); |
| if (!component_type::is_compatible(spirit::traits::which(attr_))) |
| return false; |
| |
| // returns true if any of the generators succeed |
| typedef typename component_type::compatible_type compatible_type; |
| return component.generate(sink, ctx, d, get<compatible_type>(attr_)); |
| } |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // alternative_generate_function: a functor supplied to fusion::any which |
| // will be executed for every generator in a given alternative generator |
| // expression |
| /////////////////////////////////////////////////////////////////////////// |
| template <typename OutputIterator, typename Context, typename Delimiter, |
| typename Attribute, typename Strict> |
| struct alternative_generate_function |
| { |
| alternative_generate_function(OutputIterator& sink_, Context& ctx_ |
| , Delimiter const& d, Attribute const& attr_) |
| : sink(sink_), ctx(ctx_), delim(d), attr(attr_) {} |
| |
| template <typename Component> |
| bool operator()(Component const& component) |
| { |
| typedef |
| typename traits::attribute_of<Component, Context>::type |
| expected_type; |
| typedef |
| alternative_generate<Component, Attribute, expected_type> |
| generate; |
| |
| // wrap the given output iterator avoid output as long as one |
| // component fails |
| detail::enable_buffering<OutputIterator> buffering(sink); |
| bool r = false; |
| bool failed = false; // will be ignored |
| { |
| detail::disable_counting<OutputIterator> nocounting(sink); |
| r = generate::call(component, sink, ctx, delim, attr, failed); |
| } |
| if (r) |
| buffering.buffer_copy(); |
| return r; |
| } |
| |
| // avoid double buffering |
| template <typename Component> |
| bool operator()(buffer_directive<Component> const& component) |
| { |
| typedef typename |
| traits::attribute_of<Component, Context>::type |
| expected_type; |
| typedef alternative_generate< |
| buffer_directive<Component>, Attribute, expected_type> |
| generate; |
| |
| bool failed = false; // will be ignored |
| return generate::call(component, sink, ctx, delim, attr, failed); |
| } |
| |
| OutputIterator& sink; |
| Context& ctx; |
| Delimiter const& delim; |
| Attribute const& attr; |
| |
| private: |
| // silence MSVC warning C4512: assignment operator could not be generated |
| alternative_generate_function& operator= (alternative_generate_function const&); |
| }; |
| |
| // specialization for strict alternatives |
| template <typename OutputIterator, typename Context, typename Delimiter, |
| typename Attribute> |
| struct alternative_generate_function< |
| OutputIterator, Context, Delimiter, Attribute, mpl::true_> |
| { |
| alternative_generate_function(OutputIterator& sink_, Context& ctx_ |
| , Delimiter const& d, Attribute const& attr_) |
| : sink(sink_), ctx(ctx_), delim(d), attr(attr_), failed(false) {} |
| |
| template <typename Component> |
| bool operator()(Component const& component) |
| { |
| typedef |
| typename traits::attribute_of<Component, Context>::type |
| expected_type; |
| typedef |
| alternative_generate<Component, Attribute, expected_type> |
| generate; |
| |
| if (failed) |
| return false; // give up when already failed |
| |
| // wrap the given output iterator avoid output as long as one |
| // component fails |
| detail::enable_buffering<OutputIterator> buffering(sink); |
| bool r = false; |
| { |
| detail::disable_counting<OutputIterator> nocounting(sink); |
| r = generate::call(component, sink, ctx, delim, attr, failed); |
| } |
| if (r && !failed) |
| { |
| buffering.buffer_copy(); |
| return true; |
| } |
| return false; |
| } |
| |
| OutputIterator& sink; |
| Context& ctx; |
| Delimiter const& delim; |
| Attribute const& attr; |
| bool failed; |
| |
| private: |
| // silence MSVC warning C4512: assignment operator could not be generated |
| alternative_generate_function& operator= (alternative_generate_function const&); |
| }; |
| }}}} |
| |
| #endif |