// 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace spirit { namespace tag { template 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 struct stream_generator : spirit::terminal > {}; } /////////////////////////////////////////////////////////////////////////// // Enablers /////////////////////////////////////////////////////////////////////////// template <> struct use_terminal // enables stream : mpl::true_ {}; template <> struct use_terminal // enables wstream : mpl::true_ {}; template struct use_terminal > > : mpl::true_ {}; template struct use_terminal > > : 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 template struct use_terminal > : mpl::true_ {}; template struct use_terminal, fusion::vector1 > > : mpl::true_ {}; template struct use_lazy_terminal< karma::domain, tag::stream_tag, 1 /*arity*/ > : mpl::true_ {}; }} /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace spirit { namespace karma { using spirit::stream; using spirit::wstream; /////////////////////////////////////////////////////////////////////////// template struct any_stream_generator : primitive_generator > { template 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::type attribute_type; boost::iostreams::stream ostr(sink); ostr << traits::extract_from(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, Properties >& sink, Context& context, Delimiter const& d , Attribute const& attr) { typedef karma::detail::output_iterator< karma::ostream_iterator, 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::type attribute_type; boost::iostreams::stream ostr(sink); ostr.imbue(sink.get_ostream().getloc()); ostr << traits::extract_from(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 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 info what(Context& /*context*/) const { return info("stream"); } }; template struct lit_stream_generator : primitive_generator > { template struct attribute { typedef unused_type type; }; lit_stream_generator(typename add_reference::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 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, Properties >& sink, Context&, Delimiter const& d, Attribute const&) { typedef karma::detail::output_iterator< karma::ostream_iterator, Properties > output_iterator; typedef karma::detail::iterator_sink< output_iterator, Char, CharEncoding, Tag > sink_device; boost::iostreams::stream 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 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 struct make_stream { static bool const lower = has_modifier >::value; static bool const upper = has_modifier >::value; typedef any_stream_generator< Char , typename spirit::detail::get_encoding_with_case< Modifiers, unused_type, lower || upper>::type , typename detail::get_casetag::type > result_type; result_type operator()(unused_type, unused_type) const { return result_type(); } }; // stream template struct make_primitive : make_stream {}; // wstream template struct make_primitive : make_stream {}; // any_stream_generator template struct make_primitive, Modifiers> : make_stream {}; /////////////////////////////////////////////////////////////////////////// template struct make_any_stream { static bool const lower = has_modifier >::value; static bool const upper = has_modifier >::value; typedef typename add_const::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::type > result_type; template result_type operator()(Terminal const& term, unused_type) const { return result_type(fusion::at_c<0>(term.args)); } }; // stream(...) template struct make_primitive< terminal_ex >, Modifiers> : make_any_stream {}; // wstream(...) template struct make_primitive< terminal_ex >, Modifiers> : make_any_stream {}; // any_stream_generator(...) template struct make_primitive< terminal_ex, fusion::vector1 > , Modifiers> : make_any_stream {}; }}} #endif