1 // Copyright (c) 2001-2011 Hartmut Kaiser
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 #if !defined(BOOST_SPIRIT_KARMA_STREAM_MAY_01_2007_0310PM)
7 #define BOOST_SPIRIT_KARMA_STREAM_MAY_01_2007_0310PM
13 #include <boost/spirit/home/support/common_terminals.hpp>
14 #include <boost/spirit/home/support/info.hpp>
15 #include <boost/spirit/home/support/container.hpp>
16 #include <boost/spirit/home/support/detail/hold_any.hpp>
17 #include <boost/spirit/home/support/detail/get_encoding.hpp>
18 #include <boost/spirit/home/support/detail/is_spirit_tag.hpp>
19 #include <boost/spirit/home/karma/domain.hpp>
20 #include <boost/spirit/home/karma/meta_compiler.hpp>
21 #include <boost/spirit/home/karma/delimit_out.hpp>
22 #include <boost/spirit/home/karma/auxiliary/lazy.hpp>
23 #include <boost/spirit/home/karma/stream/detail/format_manip.hpp>
24 #include <boost/spirit/home/karma/detail/generate_to.hpp>
25 #include <boost/spirit/home/karma/detail/get_casetag.hpp>
26 #include <boost/spirit/home/karma/detail/extract_from.hpp>
27 #include <boost/fusion/include/at.hpp>
28 #include <boost/fusion/include/vector.hpp>
29 #include <boost/fusion/include/cons.hpp>
30 #include <boost/utility/enable_if.hpp>
31 #include <boost/type_traits/is_same.hpp>
34 ///////////////////////////////////////////////////////////////////////////////
35 namespace boost { namespace spirit
39 template <typename Char = char>
48 ///////////////////////////////////////////////////////////////////////
49 // This one is the class that the user can instantiate directly in
50 // order to create a customized int generator
51 template <typename Char = char>
52 struct stream_generator
53 : spirit::terminal<tag::stream_tag<Char> >
57 ///////////////////////////////////////////////////////////////////////////
59 ///////////////////////////////////////////////////////////////////////////
61 struct use_terminal<karma::domain, tag::stream> // enables stream
65 struct use_terminal<karma::domain, tag::wstream> // enables wstream
68 template <typename A0>
69 struct use_terminal<karma::domain // enables stream(...)
70 , terminal_ex<tag::stream, fusion::vector1<A0> >
73 template <typename A0>
74 struct use_terminal<karma::domain // enables wstream(...)
75 , terminal_ex<tag::wstream, fusion::vector1<A0> >
78 template <> // enables stream(f)
79 struct use_lazy_terminal<
80 karma::domain, tag::stream, 1 /*arity*/
83 template <> // enables wstream(f)
84 struct use_lazy_terminal<
85 karma::domain, tag::wstream, 1 /*arity*/
88 // enables stream_generator<char_type>
89 template <typename Char>
90 struct use_terminal<karma::domain, tag::stream_tag<Char> >
93 template <typename Char, typename A0>
94 struct use_terminal<karma::domain
95 , terminal_ex<tag::stream_tag<Char>, fusion::vector1<A0> >
98 template <typename Char>
99 struct use_lazy_terminal<
100 karma::domain, tag::stream_tag<Char>, 1 /*arity*/
105 ///////////////////////////////////////////////////////////////////////////////
106 namespace boost { namespace spirit { namespace karma
108 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
109 using spirit::stream;
110 using spirit::wstream;
112 using spirit::stream_type;
113 using spirit::wstream_type;
117 template <typename OutputIterator, typename Char, typename CharEncoding
119 struct psbuf : std::basic_streambuf<Char>
121 psbuf(OutputIterator& sink) : sink_(sink) {}
123 // silence MSVC warning C4512: assignment operator could not be generated
124 BOOST_DELETED_FUNCTION(psbuf& operator=(psbuf const&))
127 typename psbuf::int_type overflow(typename psbuf::int_type ch) BOOST_OVERRIDE
129 if (psbuf::traits_type::eq_int_type(ch, psbuf::traits_type::eof()))
130 return psbuf::traits_type::not_eof(ch);
132 return detail::generate_to(sink_, psbuf::traits_type::to_char_type(ch),
133 CharEncoding(), Tag()) ? ch : psbuf::traits_type::eof();
137 OutputIterator& sink_;
141 ///////////////////////////////////////////////////////////////////////////
142 template <typename Char, typename CharEncoding, typename Tag>
143 struct any_stream_generator
144 : primitive_generator<any_stream_generator<Char, CharEncoding, Tag> >
146 template <typename Context, typename Unused = unused_type>
149 typedef spirit::basic_hold_any<Char> type;
152 // any_stream_generator has an attached attribute
154 typename OutputIterator, typename Context, typename Delimiter
157 static bool generate(OutputIterator& sink, Context& context
158 , Delimiter const& d, Attribute const& attr)
160 if (!traits::has_optional_value(attr))
163 // use existing operator<<()
164 typedef typename attribute<Context>::type attribute_type;
167 detail::psbuf<OutputIterator, Char, CharEncoding, Tag> pseudobuf(sink);
168 std::basic_ostream<Char> ostr(&pseudobuf);
169 ostr << traits::extract_from<attribute_type>(attr, context) << std::flush;
175 return karma::delimit_out(sink, d); // always do post-delimiting
178 // this is a special overload to detect if the output iterator has been
179 // generated by a format_manip object.
181 typename T, typename Traits, typename Properties, typename Context
182 , typename Delimiter, typename Attribute
184 static bool generate(
185 karma::detail::output_iterator<
186 karma::ostream_iterator<T, Char, Traits>, Properties
187 >& sink, Context& context, Delimiter const& d
188 , Attribute const& attr)
190 typedef karma::detail::output_iterator<
191 karma::ostream_iterator<T, Char, Traits>, Properties
194 if (!traits::has_optional_value(attr))
197 // use existing operator<<()
198 typedef typename attribute<Context>::type attribute_type;
201 detail::psbuf<output_iterator, Char, CharEncoding, Tag> pseudobuf(sink);
202 std::basic_ostream<Char> ostr(&pseudobuf);
203 ostr.imbue(sink.get_ostream().getloc());
204 ostr << traits::extract_from<attribute_type>(attr, context)
210 return karma::delimit_out(sink, d); // always do post-delimiting
213 // this any_stream has no parameter attached, it needs to have been
214 // initialized from a value/variable
215 template <typename OutputIterator, typename Context
216 , typename Delimiter>
218 generate(OutputIterator&, Context&, Delimiter const&, unused_type)
220 // It is not possible (doesn't make sense) to use stream generators
221 // without providing any attribute, as the generator doesn't 'know'
222 // what to output. The following assertion fires if this situation
223 // is detected in your code.
224 BOOST_SPIRIT_ASSERT_FAIL(OutputIterator, stream_not_usable_without_attribute, ());
228 template <typename Context>
229 info what(Context& /*context*/) const
231 return info("stream");
235 template <typename T, typename Char, typename CharEncoding, typename Tag>
236 struct lit_stream_generator
237 : primitive_generator<lit_stream_generator<T, Char, CharEncoding, Tag> >
239 template <typename Context, typename Unused>
242 typedef unused_type type;
245 lit_stream_generator(typename add_reference<T>::type t)
249 // lit_stream_generator has an attached parameter
251 // this overload will be used in the normal case (not called from
254 typename OutputIterator, typename Context, typename Delimiter
255 , typename Attribute>
256 bool generate(OutputIterator& sink, Context&, Delimiter const& d
257 , Attribute const&) const
259 detail::psbuf<OutputIterator, Char, CharEncoding, Tag> pseudobuf(sink);
260 std::basic_ostream<Char> ostr(&pseudobuf);
261 ostr << t_ << std::flush; // use existing operator<<()
264 return karma::delimit_out(sink, d); // always do post-delimiting
268 // this is a special overload to detect if the output iterator has been
269 // generated by a format_manip object.
271 typename T1, typename Traits, typename Properties
272 , typename Context, typename Delimiter, typename Attribute>
274 karma::detail::output_iterator<
275 karma::ostream_iterator<T1, Char, Traits>, Properties
276 >& sink, Context&, Delimiter const& d, Attribute const&) const
278 typedef karma::detail::output_iterator<
279 karma::ostream_iterator<T1, Char, Traits>, Properties
283 detail::psbuf<output_iterator, Char, CharEncoding, Tag> pseudobuf(sink);
284 std::basic_ostream<Char> ostr(&pseudobuf);
285 ostr.imbue(sink.get_ostream().getloc());
286 ostr << t_ << std::flush; // use existing operator<<()
292 return karma::delimit_out(sink, d); // always do post-delimiting
295 template <typename Context>
296 info what(Context& /*context*/) const
298 return info("any-stream");
303 // silence MSVC warning C4512: assignment operator could not be generated
304 BOOST_DELETED_FUNCTION(lit_stream_generator& operator= (lit_stream_generator const&))
307 ///////////////////////////////////////////////////////////////////////////
308 // Generator generators: make_xxx function (objects)
309 ///////////////////////////////////////////////////////////////////////////
310 template <typename Char, typename Modifiers>
313 static bool const lower =
314 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
316 static bool const upper =
317 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
319 typedef any_stream_generator<
321 , typename spirit::detail::get_encoding_with_case<
322 Modifiers, unused_type, lower || upper>::type
323 , typename detail::get_casetag<Modifiers, lower || upper>::type
326 result_type operator()(unused_type, unused_type) const
328 return result_type();
333 template <typename Modifiers>
334 struct make_primitive<tag::stream, Modifiers>
335 : make_stream<char, Modifiers> {};
338 template <typename Modifiers>
339 struct make_primitive<tag::wstream, Modifiers>
340 : make_stream<wchar_t, Modifiers> {};
342 // any_stream_generator<char_type>
343 template <typename Char, typename Modifiers>
344 struct make_primitive<tag::stream_tag<Char>, Modifiers>
345 : make_stream<Char, Modifiers> {};
347 ///////////////////////////////////////////////////////////////////////////
348 template <typename Char, typename A0, typename Modifiers>
349 struct make_any_stream
351 static bool const lower =
352 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
354 static bool const upper =
355 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
357 typedef typename add_const<A0>::type const_attribute;
358 typedef lit_stream_generator<
359 const_attribute, Char
360 , typename spirit::detail::get_encoding_with_case<
361 Modifiers, unused_type, lower || upper>::type
362 , typename detail::get_casetag<Modifiers, lower || upper>::type
365 template <typename Terminal>
366 result_type operator()(Terminal const& term, unused_type) const
368 return result_type(fusion::at_c<0>(term.args));
373 template <typename Modifiers, typename A0>
374 struct make_primitive<
375 terminal_ex<tag::stream, fusion::vector1<A0> >, Modifiers>
376 : make_any_stream<char, A0, Modifiers> {};
379 template <typename Modifiers, typename A0>
380 struct make_primitive<
381 terminal_ex<tag::wstream, fusion::vector1<A0> >, Modifiers>
382 : make_any_stream<wchar_t, A0, Modifiers> {};
384 // any_stream_generator<char_type>(...)
385 template <typename Char, typename Modifiers, typename A0>
386 struct make_primitive<
387 terminal_ex<tag::stream_tag<Char>, fusion::vector1<A0> >
389 : make_any_stream<Char, A0, Modifiers> {};