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/stream/detail/iterator_sink.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>
35 ///////////////////////////////////////////////////////////////////////////////
36 namespace boost { namespace spirit
40 template <typename Char = char>
49 ///////////////////////////////////////////////////////////////////////
50 // This one is the class that the user can instantiate directly in
51 // order to create a customized int generator
52 template <typename Char = char>
53 struct stream_generator
54 : spirit::terminal<tag::stream_tag<Char> >
58 ///////////////////////////////////////////////////////////////////////////
60 ///////////////////////////////////////////////////////////////////////////
62 struct use_terminal<karma::domain, tag::stream> // enables stream
66 struct use_terminal<karma::domain, tag::wstream> // enables wstream
69 template <typename A0>
70 struct use_terminal<karma::domain // enables stream(...)
71 , terminal_ex<tag::stream, fusion::vector1<A0> >
74 template <typename A0>
75 struct use_terminal<karma::domain // enables wstream(...)
76 , terminal_ex<tag::wstream, fusion::vector1<A0> >
79 template <> // enables stream(f)
80 struct use_lazy_terminal<
81 karma::domain, tag::stream, 1 /*arity*/
84 template <> // enables wstream(f)
85 struct use_lazy_terminal<
86 karma::domain, tag::wstream, 1 /*arity*/
89 // enables stream_generator<char_type>
90 template <typename Char>
91 struct use_terminal<karma::domain, tag::stream_tag<Char> >
94 template <typename Char, typename A0>
95 struct use_terminal<karma::domain
96 , terminal_ex<tag::stream_tag<Char>, fusion::vector1<A0> >
99 template <typename Char>
100 struct use_lazy_terminal<
101 karma::domain, tag::stream_tag<Char>, 1 /*arity*/
106 ///////////////////////////////////////////////////////////////////////////////
107 namespace boost { namespace spirit { namespace karma
109 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
110 using spirit::stream;
111 using spirit::wstream;
113 using spirit::stream_type;
114 using spirit::wstream_type;
116 ///////////////////////////////////////////////////////////////////////////
117 template <typename Char, typename CharEncoding, typename Tag>
118 struct any_stream_generator
119 : primitive_generator<any_stream_generator<Char, CharEncoding, Tag> >
121 template <typename Context, typename Unused = unused_type>
124 typedef spirit::basic_hold_any<Char> type;
127 // any_stream_generator has an attached attribute
129 typename OutputIterator, typename Context, typename Delimiter
132 static bool generate(OutputIterator& sink, Context& context
133 , Delimiter const& d, Attribute const& attr)
135 typedef karma::detail::iterator_sink<
136 OutputIterator, Char, CharEncoding, Tag
139 if (!traits::has_optional_value(attr))
142 // use existing operator<<()
143 typedef typename attribute<Context>::type attribute_type;
146 boost::iostreams::stream<sink_device> ostr(sink);
147 ostr << traits::extract_from<attribute_type>(attr, context) << std::flush;
153 return karma::delimit_out(sink, d); // always do post-delimiting
156 // this is a special overload to detect if the output iterator has been
157 // generated by a format_manip object.
159 typename T, typename Traits, typename Properties, typename Context
160 , typename Delimiter, typename Attribute
162 static bool generate(
163 karma::detail::output_iterator<
164 karma::ostream_iterator<T, Char, Traits>, Properties
165 >& sink, Context& context, Delimiter const& d
166 , Attribute const& attr)
168 typedef karma::detail::output_iterator<
169 karma::ostream_iterator<T, Char, Traits>, Properties
171 typedef karma::detail::iterator_sink<
172 output_iterator, Char, CharEncoding, Tag
175 if (!traits::has_optional_value(attr))
178 // use existing operator<<()
179 typedef typename attribute<Context>::type attribute_type;
182 boost::iostreams::stream<sink_device> ostr(sink);
183 ostr.imbue(sink.get_ostream().getloc());
184 ostr << traits::extract_from<attribute_type>(attr, context)
190 return karma::delimit_out(sink, d); // always do post-delimiting
193 // this any_stream has no parameter attached, it needs to have been
194 // initialized from a value/variable
195 template <typename OutputIterator, typename Context
196 , typename Delimiter>
198 generate(OutputIterator&, Context&, Delimiter const&, unused_type)
200 // It is not possible (doesn't make sense) to use stream generators
201 // without providing any attribute, as the generator doesn't 'know'
202 // what to output. The following assertion fires if this situation
203 // is detected in your code.
204 BOOST_SPIRIT_ASSERT_FAIL(OutputIterator, stream_not_usable_without_attribute, ());
208 template <typename Context>
209 info what(Context& /*context*/) const
211 return info("stream");
215 template <typename T, typename Char, typename CharEncoding, typename Tag>
216 struct lit_stream_generator
217 : primitive_generator<lit_stream_generator<T, Char, CharEncoding, Tag> >
219 template <typename Context, typename Unused>
222 typedef unused_type type;
225 lit_stream_generator(typename add_reference<T>::type t)
229 // lit_stream_generator has an attached parameter
231 // this overload will be used in the normal case (not called from
234 typename OutputIterator, typename Context, typename Delimiter
235 , typename Attribute>
236 bool generate(OutputIterator& sink, Context&, Delimiter const& d
237 , Attribute const&) const
239 typedef karma::detail::iterator_sink<
240 OutputIterator, Char, CharEncoding, Tag
243 boost::iostreams::stream<sink_device> ostr(sink);
244 ostr << t_ << std::flush; // use existing operator<<()
247 return karma::delimit_out(sink, d); // always do post-delimiting
251 // this is a special overload to detect if the output iterator has been
252 // generated by a format_manip object.
254 typename T1, typename Traits, typename Properties
255 , typename Context, typename Delimiter, typename Attribute>
257 karma::detail::output_iterator<
258 karma::ostream_iterator<T1, Char, Traits>, Properties
259 >& sink, Context&, Delimiter const& d, Attribute const&) const
261 typedef karma::detail::output_iterator<
262 karma::ostream_iterator<T1, Char, Traits>, Properties
264 typedef karma::detail::iterator_sink<
265 output_iterator, Char, CharEncoding, Tag
269 boost::iostreams::stream<sink_device> ostr(sink);
270 ostr.imbue(sink.get_ostream().getloc());
271 ostr << t_ << std::flush; // use existing operator<<()
277 return karma::delimit_out(sink, d); // always do post-delimiting
280 template <typename Context>
281 info what(Context& /*context*/) const
283 return info("any-stream");
289 // silence MSVC warning C4512: assignment operator could not be generated
290 lit_stream_generator& operator= (lit_stream_generator const&);
293 ///////////////////////////////////////////////////////////////////////////
294 // Generator generators: make_xxx function (objects)
295 ///////////////////////////////////////////////////////////////////////////
296 template <typename Char, typename Modifiers>
299 static bool const lower =
300 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
302 static bool const upper =
303 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
305 typedef any_stream_generator<
307 , typename spirit::detail::get_encoding_with_case<
308 Modifiers, unused_type, lower || upper>::type
309 , typename detail::get_casetag<Modifiers, lower || upper>::type
312 result_type operator()(unused_type, unused_type) const
314 return result_type();
319 template <typename Modifiers>
320 struct make_primitive<tag::stream, Modifiers>
321 : make_stream<char, Modifiers> {};
324 template <typename Modifiers>
325 struct make_primitive<tag::wstream, Modifiers>
326 : make_stream<wchar_t, Modifiers> {};
328 // any_stream_generator<char_type>
329 template <typename Char, typename Modifiers>
330 struct make_primitive<tag::stream_tag<Char>, Modifiers>
331 : make_stream<Char, Modifiers> {};
333 ///////////////////////////////////////////////////////////////////////////
334 template <typename Char, typename A0, typename Modifiers>
335 struct make_any_stream
337 static bool const lower =
338 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
340 static bool const upper =
341 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
343 typedef typename add_const<A0>::type const_attribute;
344 typedef lit_stream_generator<
345 const_attribute, Char
346 , typename spirit::detail::get_encoding_with_case<
347 Modifiers, unused_type, lower || upper>::type
348 , typename detail::get_casetag<Modifiers, lower || upper>::type
351 template <typename Terminal>
352 result_type operator()(Terminal const& term, unused_type) const
354 return result_type(fusion::at_c<0>(term.args));
359 template <typename Modifiers, typename A0>
360 struct make_primitive<
361 terminal_ex<tag::stream, fusion::vector1<A0> >, Modifiers>
362 : make_any_stream<char, A0, Modifiers> {};
365 template <typename Modifiers, typename A0>
366 struct make_primitive<
367 terminal_ex<tag::wstream, fusion::vector1<A0> >, Modifiers>
368 : make_any_stream<wchar_t, A0, Modifiers> {};
370 // any_stream_generator<char_type>(...)
371 template <typename Char, typename Modifiers, typename A0>
372 struct make_primitive<
373 terminal_ex<tag::stream_tag<Char>, fusion::vector1<A0> >
375 : make_any_stream<Char, A0, Modifiers> {};