1// Copyright (c) 2001-2011 Hartmut Kaiser
2//
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)
5
6#if !defined(BOOST_SPIRIT_KARMA_STREAM_MAY_01_2007_0310PM)
7#define BOOST_SPIRIT_KARMA_STREAM_MAY_01_2007_0310PM
8
9#if defined(_MSC_VER)
10#pragma once
11#endif
12
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/core/enable_if.hpp>
31#include <boost/mpl/bool.hpp>
32#include <boost/type_traits/is_same.hpp>
33#include <ostream>
34
35///////////////////////////////////////////////////////////////////////////////
36namespace boost { namespace spirit
37{
38 namespace tag
39 {
40 template <typename Char = char>
41 struct stream_tag
42 {
43 BOOST_SPIRIT_IS_TAG()
44 };
45 }
46
47 namespace karma
48 {
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> >
55 {};
56 }
57
58 ///////////////////////////////////////////////////////////////////////////
59 // Enablers
60 ///////////////////////////////////////////////////////////////////////////
61 template <>
62 struct use_terminal<karma::domain, tag::stream> // enables stream
63 : mpl::true_ {};
64
65 template <>
66 struct use_terminal<karma::domain, tag::wstream> // enables wstream
67 : mpl::true_ {};
68
69 template <typename A0>
70 struct use_terminal<karma::domain // enables stream(...)
71 , terminal_ex<tag::stream, fusion::vector1<A0> >
72 > : mpl::true_ {};
73
74 template <typename A0>
75 struct use_terminal<karma::domain // enables wstream(...)
76 , terminal_ex<tag::wstream, fusion::vector1<A0> >
77 > : mpl::true_ {};
78
79 template <> // enables stream(f)
80 struct use_lazy_terminal<
81 karma::domain, tag::stream, 1 /*arity*/
82 > : mpl::true_ {};
83
84 template <> // enables wstream(f)
85 struct use_lazy_terminal<
86 karma::domain, tag::wstream, 1 /*arity*/
87 > : mpl::true_ {};
88
89 // enables stream_generator<char_type>
90 template <typename Char>
91 struct use_terminal<karma::domain, tag::stream_tag<Char> >
92 : mpl::true_ {};
93
94 template <typename Char, typename A0>
95 struct use_terminal<karma::domain
96 , terminal_ex<tag::stream_tag<Char>, fusion::vector1<A0> >
97 > : mpl::true_ {};
98
99 template <typename Char>
100 struct use_lazy_terminal<
101 karma::domain, tag::stream_tag<Char>, 1 /*arity*/
102 > : mpl::true_ {};
103
104}}
105
106///////////////////////////////////////////////////////////////////////////////
107namespace boost { namespace spirit { namespace karma
108{
109#ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
110 using spirit::stream;
111 using spirit::wstream;
112#endif
113 using spirit::stream_type;
114 using spirit::wstream_type;
115
116namespace detail
117{
118#ifdef _MSC_VER
119# pragma warning(push)
120# pragma warning(disable: 4512) // assignment operator could not be generated.
121#endif
122 template <typename OutputIterator, typename Char, typename CharEncoding
123 , typename Tag>
124 struct psbuf : std::basic_streambuf<Char>
125 {
126 psbuf(OutputIterator& sink) : sink_(sink) {}
127
128 protected:
129 typename psbuf::int_type overflow(typename psbuf::int_type ch) BOOST_OVERRIDE
130 {
131 if (psbuf::traits_type::eq_int_type(ch, psbuf::traits_type::eof()))
132 return psbuf::traits_type::not_eof(ch);
133
134 return detail::generate_to(sink_, psbuf::traits_type::to_char_type(ch),
135 CharEncoding(), Tag()) ? ch : psbuf::traits_type::eof();
136 }
137
138 private:
139 OutputIterator& sink_;
140 };
141#ifdef _MSC_VER
142# pragma warning(pop)
143#endif
144}
145
146 ///////////////////////////////////////////////////////////////////////////
147 template <typename Char, typename CharEncoding, typename Tag>
148 struct any_stream_generator
149 : primitive_generator<any_stream_generator<Char, CharEncoding, Tag> >
150 {
151 template <typename Context, typename Unused = unused_type>
152 struct attribute
153 {
154 typedef spirit::basic_hold_any<Char> type;
155 };
156
157 // any_stream_generator has an attached attribute
158 template <
159 typename OutputIterator, typename Context, typename Delimiter
160 , typename Attribute
161 >
162 static bool generate(OutputIterator& sink, Context& context
163 , Delimiter const& d, Attribute const& attr)
164 {
165 if (!traits::has_optional_value(attr))
166 return false;
167
168 // use existing operator<<()
169 typedef typename attribute<Context>::type attribute_type;
170
171 {
172 detail::psbuf<OutputIterator, Char, CharEncoding, Tag> pseudobuf(sink);
173 std::basic_ostream<Char> ostr(&pseudobuf);
174 ostr << traits::extract_from<attribute_type>(attr, context) << std::flush;
175
176 if (!ostr.good())
177 return false;
178 }
179
180 return karma::delimit_out(sink, d); // always do post-delimiting
181 }
182
183 // this is a special overload to detect if the output iterator has been
184 // generated by a format_manip object.
185 template <
186 typename T, typename Traits, typename Properties, typename Context
187 , typename Delimiter, typename Attribute
188 >
189 static bool generate(
190 karma::detail::output_iterator<
191 karma::ostream_iterator<T, Char, Traits>, Properties
192 >& sink, Context& context, Delimiter const& d
193 , Attribute const& attr)
194 {
195 typedef karma::detail::output_iterator<
196 karma::ostream_iterator<T, Char, Traits>, Properties
197 > output_iterator;
198
199 if (!traits::has_optional_value(attr))
200 return false;
201
202 // use existing operator<<()
203 typedef typename attribute<Context>::type attribute_type;
204
205 {
206 detail::psbuf<output_iterator, Char, CharEncoding, Tag> pseudobuf(sink);
207 std::basic_ostream<Char> ostr(&pseudobuf);
208 ostr.imbue(sink.get_ostream().getloc());
209 ostr << traits::extract_from<attribute_type>(attr, context)
210 << std::flush;
211 if (!ostr.good())
212 return false;
213 }
214
215 return karma::delimit_out(sink, d); // always do post-delimiting
216 }
217
218 // this any_stream has no parameter attached, it needs to have been
219 // initialized from a value/variable
220 template <typename OutputIterator, typename Context
221 , typename Delimiter>
222 static bool
223 generate(OutputIterator&, Context&, Delimiter const&, unused_type)
224 {
225 // It is not possible (doesn't make sense) to use stream generators
226 // without providing any attribute, as the generator doesn't 'know'
227 // what to output. The following assertion fires if this situation
228 // is detected in your code.
229 BOOST_SPIRIT_ASSERT_FAIL(OutputIterator, stream_not_usable_without_attribute, ());
230 return false;
231 }
232
233 template <typename Context>
234 info what(Context& /*context*/) const
235 {
236 return info("stream");
237 }
238 };
239
240 template <typename T, typename Char, typename CharEncoding, typename Tag>
241 struct lit_stream_generator
242 : primitive_generator<lit_stream_generator<T, Char, CharEncoding, Tag> >
243 {
244 template <typename Context, typename Unused>
245 struct attribute
246 {
247 typedef unused_type type;
248 };
249
250 lit_stream_generator(typename add_reference<T>::type t)
251 : t_(t)
252 {}
253
254 // lit_stream_generator has an attached parameter
255
256 // this overload will be used in the normal case (not called from
257 // format_manip).
258 template <
259 typename OutputIterator, typename Context, typename Delimiter
260 , typename Attribute>
261 bool generate(OutputIterator& sink, Context&, Delimiter const& d
262 , Attribute const&) const
263 {
264 detail::psbuf<OutputIterator, Char, CharEncoding, Tag> pseudobuf(sink);
265 std::basic_ostream<Char> ostr(&pseudobuf);
266 ostr << t_ << std::flush; // use existing operator<<()
267
268 if (ostr.good())
269 return karma::delimit_out(sink, d); // always do post-delimiting
270 return false;
271 }
272
273 // this is a special overload to detect if the output iterator has been
274 // generated by a format_manip object.
275 template <
276 typename T1, typename Traits, typename Properties
277 , typename Context, typename Delimiter, typename Attribute>
278 bool generate(
279 karma::detail::output_iterator<
280 karma::ostream_iterator<T1, Char, Traits>, Properties
281 >& sink, Context&, Delimiter const& d, Attribute const&) const
282 {
283 typedef karma::detail::output_iterator<
284 karma::ostream_iterator<T1, Char, Traits>, Properties
285 > output_iterator;
286
287 {
288 detail::psbuf<output_iterator, Char, CharEncoding, Tag> pseudobuf(sink);
289 std::basic_ostream<Char> ostr(&pseudobuf);
290 ostr.imbue(sink.get_ostream().getloc());
291 ostr << t_ << std::flush; // use existing operator<<()
292
293 if (!ostr.good())
294 return false;
295 }
296
297 return karma::delimit_out(sink, d); // always do post-delimiting
298 }
299
300 template <typename Context>
301 info what(Context& /*context*/) const
302 {
303 return info("any-stream");
304 }
305
306 T t_;
307 };
308
309 ///////////////////////////////////////////////////////////////////////////
310 // Generator generators: make_xxx function (objects)
311 ///////////////////////////////////////////////////////////////////////////
312 template <typename Char, typename Modifiers>
313 struct make_stream
314 {
315 static bool const lower =
316 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
317
318 static bool const upper =
319 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
320
321 typedef any_stream_generator<
322 Char
323 , typename spirit::detail::get_encoding_with_case<
324 Modifiers, unused_type, lower || upper>::type
325 , typename detail::get_casetag<Modifiers, lower || upper>::type
326 > result_type;
327
328 result_type operator()(unused_type, unused_type) const
329 {
330 return result_type();
331 }
332 };
333
334 // stream
335 template <typename Modifiers>
336 struct make_primitive<tag::stream, Modifiers>
337 : make_stream<char, Modifiers> {};
338
339 // wstream
340 template <typename Modifiers>
341 struct make_primitive<tag::wstream, Modifiers>
342 : make_stream<wchar_t, Modifiers> {};
343
344 // any_stream_generator<char_type>
345 template <typename Char, typename Modifiers>
346 struct make_primitive<tag::stream_tag<Char>, Modifiers>
347 : make_stream<Char, Modifiers> {};
348
349 ///////////////////////////////////////////////////////////////////////////
350 template <typename Char, typename A0, typename Modifiers>
351 struct make_any_stream
352 {
353 static bool const lower =
354 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
355
356 static bool const upper =
357 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
358
359 typedef typename add_const<A0>::type const_attribute;
360 typedef lit_stream_generator<
361 const_attribute, Char
362 , typename spirit::detail::get_encoding_with_case<
363 Modifiers, unused_type, lower || upper>::type
364 , typename detail::get_casetag<Modifiers, lower || upper>::type
365 > result_type;
366
367 template <typename Terminal>
368 result_type operator()(Terminal const& term, unused_type) const
369 {
370 return result_type(fusion::at_c<0>(term.args));
371 }
372 };
373
374 // stream(...)
375 template <typename Modifiers, typename A0>
376 struct make_primitive<
377 terminal_ex<tag::stream, fusion::vector1<A0> >, Modifiers>
378 : make_any_stream<char, A0, Modifiers> {};
379
380 // wstream(...)
381 template <typename Modifiers, typename A0>
382 struct make_primitive<
383 terminal_ex<tag::wstream, fusion::vector1<A0> >, Modifiers>
384 : make_any_stream<wchar_t, A0, Modifiers> {};
385
386 // any_stream_generator<char_type>(...)
387 template <typename Char, typename Modifiers, typename A0>
388 struct make_primitive<
389 terminal_ex<tag::stream_tag<Char>, fusion::vector1<A0> >
390 , Modifiers>
391 : make_any_stream<Char, A0, Modifiers> {};
392
393}}}
394
395#endif
396

source code of boost/libs/spirit/include/boost/spirit/home/karma/stream/stream.hpp