| // Copyright (c) 2001-2010 Hartmut Kaiser |
| // |
| // 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(BOOST_SPIRIT_KARMA_STREAM_MAY_01_2007_0310PM) |
| #define BOOST_SPIRIT_KARMA_STREAM_MAY_01_2007_0310PM |
| |
| #if defined(_MSC_VER) |
| #pragma once |
| #endif |
| |
| #include <boost/spirit/home/support/common_terminals.hpp> |
| #include <boost/spirit/home/support/info.hpp> |
| #include <boost/spirit/home/support/container.hpp> |
| #include <boost/spirit/home/support/detail/hold_any.hpp> |
| #include <boost/spirit/home/support/detail/get_encoding.hpp> |
| #include <boost/spirit/home/karma/domain.hpp> |
| #include <boost/spirit/home/karma/meta_compiler.hpp> |
| #include <boost/spirit/home/karma/delimit_out.hpp> |
| #include <boost/spirit/home/karma/auxiliary/lazy.hpp> |
| #include <boost/spirit/home/karma/stream/detail/format_manip.hpp> |
| #include <boost/spirit/home/karma/stream/detail/iterator_sink.hpp> |
| #include <boost/spirit/home/karma/detail/get_casetag.hpp> |
| #include <boost/spirit/home/karma/detail/extract_from.hpp> |
| #include <boost/fusion/include/at.hpp> |
| #include <boost/fusion/include/vector.hpp> |
| #include <boost/fusion/include/cons.hpp> |
| #include <boost/utility/enable_if.hpp> |
| #include <boost/type_traits/is_same.hpp> |
| |
| #include <iosfwd> |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| namespace boost { namespace spirit |
| { |
| namespace tag |
| { |
| template <typename Char = char> |
| struct stream_tag {}; |
| } |
| |
| namespace karma |
| { |
| /////////////////////////////////////////////////////////////////////// |
| // This one is the class that the user can instantiate directly in |
| // order to create a customized int generator |
| template <typename Char = char> |
| struct stream_generator |
| : spirit::terminal<tag::stream_tag<Char> > |
| {}; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // Enablers |
| /////////////////////////////////////////////////////////////////////////// |
| template <> |
| struct use_terminal<karma::domain, tag::stream> // enables stream |
| : mpl::true_ {}; |
| |
| template <> |
| struct use_terminal<karma::domain, tag::wstream> // enables wstream |
| : mpl::true_ {}; |
| |
| template <typename A0> |
| struct use_terminal<karma::domain // enables stream(...) |
| , terminal_ex<tag::stream, fusion::vector1<A0> > |
| > : mpl::true_ {}; |
| |
| template <typename A0> |
| struct use_terminal<karma::domain // enables wstream(...) |
| , terminal_ex<tag::wstream, fusion::vector1<A0> > |
| > : mpl::true_ {}; |
| |
| template <> // enables stream(f) |
| struct use_lazy_terminal< |
| karma::domain, tag::stream, 1 /*arity*/ |
| > : mpl::true_ {}; |
| |
| template <> // enables wstream(f) |
| struct use_lazy_terminal< |
| karma::domain, tag::wstream, 1 /*arity*/ |
| > : mpl::true_ {}; |
| |
| // enables stream_generator<char_type> |
| template <typename Char> |
| struct use_terminal<karma::domain, tag::stream_tag<Char> > |
| : mpl::true_ {}; |
| |
| template <typename Char, typename A0> |
| struct use_terminal<karma::domain |
| , terminal_ex<tag::stream_tag<Char>, fusion::vector1<A0> > |
| > : mpl::true_ {}; |
| |
| template <typename Char> |
| struct use_lazy_terminal< |
| karma::domain, tag::stream_tag<Char>, 1 /*arity*/ |
| > : mpl::true_ {}; |
| |
| }} |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| namespace boost { namespace spirit { namespace karma |
| { |
| using spirit::stream; |
| using spirit::wstream; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| template <typename Char, typename CharEncoding, typename Tag> |
| struct any_stream_generator |
| : primitive_generator<any_stream_generator<Char, CharEncoding, Tag> > |
| { |
| template <typename Context, typename Unused = unused_type> |
| struct attribute |
| { |
| typedef spirit::hold_any type; |
| }; |
| |
| // any_stream_generator has an attached attribute |
| template < |
| typename OutputIterator, typename Context, typename Delimiter |
| , typename Attribute |
| > |
| static bool generate(OutputIterator& sink, Context& context |
| , Delimiter const& d, Attribute const& attr) |
| { |
| typedef karma::detail::iterator_sink< |
| OutputIterator, Char, CharEncoding, Tag |
| > sink_device; |
| |
| if (!traits::has_optional_value(attr)) |
| return false; |
| |
| // use existing operator<<() |
| typedef typename attribute<Context>::type attribute_type; |
| |
| boost::iostreams::stream<sink_device> ostr(sink); |
| ostr << traits::extract_from<attribute_type>(attr, context) << std::flush; |
| |
| if (ostr.good()) |
| return karma::delimit_out(sink, d); // always do post-delimiting |
| return false; |
| } |
| |
| // this is a special overload to detect if the output iterator has been |
| // generated by a format_manip object. |
| template < |
| typename T, typename Traits, typename Properties, typename Context |
| , typename Delimiter, typename Attribute |
| > |
| static bool generate( |
| karma::detail::output_iterator< |
| karma::ostream_iterator<T, Char, Traits>, Properties |
| >& sink, Context& context, Delimiter const& d |
| , Attribute const& attr) |
| { |
| typedef karma::detail::output_iterator< |
| karma::ostream_iterator<T, Char, Traits>, Properties |
| > output_iterator; |
| typedef karma::detail::iterator_sink< |
| output_iterator, Char, CharEncoding, Tag |
| > sink_device; |
| |
| if (!traits::has_optional_value(attr)) |
| return false; |
| |
| // use existing operator<<() |
| typedef typename attribute<Context>::type attribute_type; |
| |
| boost::iostreams::stream<sink_device> ostr(sink); |
| ostr.imbue(sink.get_ostream().getloc()); |
| ostr << traits::extract_from<attribute_type>(attr, context) |
| << std::flush; |
| |
| if (ostr.good()) |
| return karma::delimit_out(sink, d); // always do post-delimiting |
| return false; |
| } |
| |
| // this any_stream has no parameter attached, it needs to have been |
| // initialized from a value/variable |
| template <typename OutputIterator, typename Context |
| , typename Delimiter> |
| static bool |
| generate(OutputIterator&, Context&, Delimiter const&, unused_type) |
| { |
| // It is not possible (doesn't make sense) to use stream generators |
| // without providing any attribute, as the generator doesn't 'know' |
| // what to output. The following assertion fires if this situation |
| // is detected in your code. |
| BOOST_SPIRIT_ASSERT_MSG(false, stream_not_usable_without_attribute, ()); |
| return false; |
| } |
| |
| template <typename Context> |
| info what(Context& /*context*/) const |
| { |
| return info("stream"); |
| } |
| }; |
| |
| template <typename T, typename Char, typename CharEncoding, typename Tag> |
| struct lit_stream_generator |
| : primitive_generator<lit_stream_generator<T, Char, CharEncoding, Tag> > |
| { |
| template <typename Context, typename Unused> |
| struct attribute |
| { |
| typedef unused_type type; |
| }; |
| |
| lit_stream_generator(typename add_reference<T>::type t) |
| : t_(t) |
| {} |
| |
| // lit_stream_generator has an attached parameter |
| |
| // this overload will be used in the normal case (not called from |
| // format_manip). |
| template < |
| typename OutputIterator, typename Context, typename Delimiter |
| , typename Attribute> |
| bool generate(OutputIterator& sink, Context&, Delimiter const& d |
| , Attribute const&) |
| { |
| typedef karma::detail::iterator_sink< |
| OutputIterator, Char, CharEncoding, Tag |
| > sink_device; |
| |
| boost::iostreams::stream<sink_device> ostr(sink); |
| ostr << t_ << std::flush; // use existing operator<<() |
| |
| if (ostr.good()) |
| return karma::delimit_out(sink, d); // always do post-delimiting |
| return false; |
| } |
| |
| // this is a special overload to detect if the output iterator has been |
| // generated by a format_manip object. |
| template < |
| typename T1, typename Traits, typename Properties |
| , typename Context, typename Delimiter, typename Attribute> |
| bool generate( |
| karma::detail::output_iterator< |
| karma::ostream_iterator<T1, Char, Traits>, Properties |
| >& sink, Context&, Delimiter const& d, Attribute const&) |
| { |
| typedef karma::detail::output_iterator< |
| karma::ostream_iterator<T1, Char, Traits>, Properties |
| > output_iterator; |
| typedef karma::detail::iterator_sink< |
| output_iterator, Char, CharEncoding, Tag |
| > sink_device; |
| |
| boost::iostreams::stream<sink_device> ostr(sink); |
| ostr.imbue(sink.get_ostream().getloc()); |
| ostr << t_ << std::flush; // use existing operator<<() |
| |
| if (ostr.good()) |
| return karma::delimit_out(sink, d); // always do post-delimiting |
| return false; |
| } |
| |
| template <typename Context> |
| info what(Context& /*context*/) const |
| { |
| return info("any-stream"); |
| } |
| |
| T t_; |
| |
| private: |
| // silence MSVC warning C4512: assignment operator could not be generated |
| lit_stream_generator& operator= (lit_stream_generator const&); |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| // Generator generators: make_xxx function (objects) |
| /////////////////////////////////////////////////////////////////////////// |
| template <typename Char, typename Modifiers> |
| struct make_stream |
| { |
| static bool const lower = |
| has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value; |
| |
| static bool const upper = |
| has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value; |
| |
| typedef any_stream_generator< |
| Char |
| , typename spirit::detail::get_encoding_with_case< |
| Modifiers, unused_type, lower || upper>::type |
| , typename detail::get_casetag<Modifiers, lower || upper>::type |
| > result_type; |
| |
| result_type operator()(unused_type, unused_type) const |
| { |
| return result_type(); |
| } |
| }; |
| |
| // stream |
| template <typename Modifiers> |
| struct make_primitive<tag::stream, Modifiers> |
| : make_stream<char, Modifiers> {}; |
| |
| // wstream |
| template <typename Modifiers> |
| struct make_primitive<tag::wstream, Modifiers> |
| : make_stream<wchar_t, Modifiers> {}; |
| |
| // any_stream_generator<char_type> |
| template <typename Char, typename Modifiers> |
| struct make_primitive<tag::stream_tag<Char>, Modifiers> |
| : make_stream<Char, Modifiers> {}; |
| |
| /////////////////////////////////////////////////////////////////////////// |
| template <typename Char, typename A0, typename Modifiers> |
| struct make_any_stream |
| { |
| static bool const lower = |
| has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value; |
| |
| static bool const upper = |
| has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value; |
| |
| typedef typename add_const<A0>::type const_attribute; |
| typedef lit_stream_generator< |
| const_attribute, Char |
| , typename spirit::detail::get_encoding_with_case< |
| Modifiers, unused_type, lower || upper>::type |
| , typename detail::get_casetag<Modifiers, lower || upper>::type |
| > result_type; |
| |
| template <typename Terminal> |
| result_type operator()(Terminal const& term, unused_type) const |
| { |
| return result_type(fusion::at_c<0>(term.args)); |
| } |
| }; |
| |
| // stream(...) |
| template <typename Modifiers, typename A0> |
| struct make_primitive< |
| terminal_ex<tag::stream, fusion::vector1<A0> >, Modifiers> |
| : make_any_stream<char, A0, Modifiers> {}; |
| |
| // wstream(...) |
| template <typename Modifiers, typename A0> |
| struct make_primitive< |
| terminal_ex<tag::wstream, fusion::vector1<A0> >, Modifiers> |
| : make_any_stream<wchar_t, A0, Modifiers> {}; |
| |
| // any_stream_generator<char_type>(...) |
| template <typename Char, typename Modifiers, typename A0> |
| struct make_primitive< |
| terminal_ex<tag::stream_tag<Char>, fusion::vector1<A0> > |
| , Modifiers> |
| : make_any_stream<Char, A0, Modifiers> {}; |
| |
| }}} |
| |
| #endif |