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_OUTPUT_ITERATOR_MAY_26_2007_0506PM)
7#define BOOST_SPIRIT_KARMA_OUTPUT_ITERATOR_MAY_26_2007_0506PM
8
9#if defined(_MSC_VER)
10#pragma once
11#endif
12
13#include <iterator>
14#include <vector>
15#include <algorithm>
16
17#include <boost/config.hpp>
18#include <boost/noncopyable.hpp>
19#include <boost/mpl/if.hpp>
20
21#include <boost/spirit/home/karma/generator.hpp>
22#include <boost/spirit/home/support/iterators/ostream_iterator.hpp>
23#include <boost/spirit/home/support/unused.hpp>
24
25#if defined(BOOST_MSVC) && defined(BOOST_SPIRIT_UNICODE)
26#include <boost/spirit/home/support/char_encoding/unicode.hpp>
27#endif
28
29namespace boost { namespace spirit { namespace karma { namespace detail
30{
31 ///////////////////////////////////////////////////////////////////////////
32 // This class is used to keep track of the current position in the output.
33 ///////////////////////////////////////////////////////////////////////////
34 class position_sink
35 {
36 public:
37 position_sink() : count(0), line(1), column(1) {}
38 void tidy() { count = 0; line = 1; column = 1; }
39
40 template <typename T>
41 void output(T const& value)
42 {
43 ++count;
44 if (value == '\n') {
45 ++line;
46 column = 1;
47 }
48 else {
49 ++column;
50 }
51 }
52 std::size_t get_count() const { return count; }
53 std::size_t get_line() const { return line; }
54 std::size_t get_column() const { return column; }
55
56 private:
57 std::size_t count;
58 std::size_t line;
59 std::size_t column;
60 };
61
62 ///////////////////////////////////////////////////////////////////////////
63 struct position_policy
64 {
65 position_policy() {}
66 position_policy(position_policy const& rhs)
67 : track_position_data(rhs.track_position_data) {}
68
69 template <typename T>
70 void output(T const& value)
71 {
72 // track position in the output
73 track_position_data.output(value);
74 }
75
76 // return the current count in the output
77 std::size_t get_out_count() const
78 {
79 return track_position_data.get_count();
80 }
81
82 // return the current line in the output
83 std::size_t get_line() const
84 {
85 return track_position_data.get_line();
86 }
87
88 // return the current column in the output
89 std::size_t get_column() const
90 {
91 return track_position_data.get_column();
92 }
93
94 private:
95 position_sink track_position_data; // for position tracking
96 };
97
98 struct no_position_policy
99 {
100 no_position_policy() {}
101 no_position_policy(no_position_policy const&) {}
102
103 template <typename T>
104 void output(T const& /*value*/) {}
105 };
106
107 ///////////////////////////////////////////////////////////////////////////
108 // This class is used to count the number of characters streamed into the
109 // output.
110 ///////////////////////////////////////////////////////////////////////////
111 template <typename OutputIterator>
112 class counting_sink : boost::noncopyable
113 {
114 public:
115 counting_sink(OutputIterator& sink_, std::size_t count_ = 0
116 , bool enabled = true)
117 : count(count_), initial_count(count), prev_count(0), sink(sink_)
118 {
119 prev_count = sink.chain_counting(enabled ? this : NULL);
120 }
121 ~counting_sink()
122 {
123 if (prev_count) // propagate count
124 prev_count->update_count(count-initial_count);
125 sink.chain_counting(prev_count);
126 }
127
128 void output()
129 {
130 ++count;
131 }
132 std::size_t get_count() const { return count; }
133
134 // propagate count from embedded counters
135 void update_count(std::size_t c)
136 {
137 count += c;
138 }
139
140 private:
141 std::size_t count;
142 std::size_t initial_count;
143 counting_sink* prev_count; // previous counter in chain
144 OutputIterator& sink;
145 };
146
147 ///////////////////////////////////////////////////////////////////////////
148 template <typename OutputIterator>
149 struct counting_policy
150 {
151 public:
152 counting_policy() : count(NULL) {}
153 counting_policy(counting_policy const& rhs) : count(rhs.count) {}
154
155 // functions related to counting
156 counting_sink<OutputIterator>* chain_counting(
157 counting_sink<OutputIterator>* count_data)
158 {
159 counting_sink<OutputIterator>* prev_count = count;
160 count = count_data;
161 return prev_count;
162 }
163
164 template <typename T>
165 void output(T const&)
166 {
167 // count characters, if appropriate
168 if (NULL != count)
169 count->output();
170 }
171
172 private:
173 counting_sink<OutputIterator>* count; // for counting
174 };
175
176 struct no_counting_policy
177 {
178 no_counting_policy() {}
179 no_counting_policy(no_counting_policy const&) {}
180
181 template <typename T>
182 void output(T const& /*value*/) {}
183 };
184
185 ///////////////////////////////////////////////////////////////////////////
186 // The following classes are used to intercept the output into a buffer
187 // allowing to do things like alignment, character escaping etc.
188 ///////////////////////////////////////////////////////////////////////////
189 class buffer_sink : boost::noncopyable
190 {
191 // wchar_t is only 16-bits on Windows. If BOOST_SPIRIT_UNICODE is
192 // defined, the character type is 32-bits wide so we need to make
193 // sure the buffer is at least that wide.
194#if (defined(_MSC_VER) || defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) && defined(BOOST_SPIRIT_UNICODE)
195 typedef spirit::char_encoding::unicode::char_type buffer_char_type;
196#else
197 typedef wchar_t buffer_char_type;
198#endif
199
200 public:
201 buffer_sink()
202 : width(0) {}
203
204 ~buffer_sink()
205 {
206 tidy();
207 }
208
209 void enable(std::size_t width_)
210 {
211 tidy(); // release existing buffer
212 width = (width_ == std::size_t(-1)) ? 0 : width_;
213 buffer.reserve(res_arg: width);
214 }
215
216 void tidy()
217 {
218 buffer.clear();
219 width = 0;
220 }
221
222 template <typename T>
223 void output(T const& value)
224 {
225 BOOST_STATIC_ASSERT(sizeof(T) <= sizeof(buffer_char_type));
226 buffer.push_back(c: value);
227 }
228
229 template <typename OutputIterator_>
230 bool copy(OutputIterator_& sink, std::size_t maxwidth) const
231 {
232#if defined(BOOST_MSVC)
233#pragma warning(push)
234#pragma warning(disable: 4267)
235#endif
236 typename std::basic_string<buffer_char_type>::const_iterator end =
237 buffer.begin() + (std::min)(a: buffer.size(), b: maxwidth);
238
239#if defined(BOOST_MSVC)
240#pragma warning(disable: 4244) // conversion from 'x' to 'y', possible loss of data
241#endif
242 std::copy(buffer.begin(), end, sink);
243#if defined(BOOST_MSVC)
244#pragma warning(pop)
245#endif
246 return true;
247 }
248 template <typename RestIterator>
249 bool copy_rest(RestIterator& sink, std::size_t start_at) const
250 {
251#if defined(BOOST_MSVC)
252#pragma warning(push)
253#pragma warning(disable: 4267)
254#endif
255 typename std::basic_string<buffer_char_type>::const_iterator begin =
256 buffer.begin() + (std::min)(a: buffer.size(), b: start_at);
257
258#if defined(BOOST_MSVC)
259#pragma warning(disable: 4244) // conversion from 'x' to 'y', possible loss of data
260#endif
261 std::copy(begin, buffer.end(), sink);
262#if defined(BOOST_MSVC)
263#pragma warning(pop)
264#endif
265 return true;
266 }
267
268 std::size_t buffer_size() const
269 {
270 return buffer.size();
271 }
272
273 private:
274 std::size_t width;
275 std::basic_string<buffer_char_type> buffer;
276 };
277
278 ///////////////////////////////////////////////////////////////////////////
279 struct buffering_policy
280 {
281 public:
282 buffering_policy() : buffer(NULL) {}
283 buffering_policy(buffering_policy const& rhs) : buffer(rhs.buffer) {}
284
285 // functions related to buffering
286 buffer_sink* chain_buffering(buffer_sink* buffer_data)
287 {
288 buffer_sink* prev_buffer = buffer;
289 buffer = buffer_data;
290 return prev_buffer;
291 }
292
293 template <typename T>
294 bool output(T const& value)
295 {
296 // buffer characters, if appropriate
297 if (NULL != buffer) {
298 buffer->output(value);
299 return false;
300 }
301 return true;
302 }
303
304 bool has_buffer() const { return NULL != buffer; }
305
306 private:
307 buffer_sink* buffer;
308 };
309
310 struct no_buffering_policy
311 {
312 no_buffering_policy() {}
313 no_buffering_policy(no_buffering_policy const&) {}
314
315 template <typename T>
316 bool output(T const& /*value*/)
317 {
318 return true;
319 }
320
321 bool has_buffer() const { return false; }
322 };
323
324 ///////////////////////////////////////////////////////////////////////////
325 // forward declaration only
326 template <typename OutputIterator>
327 struct enable_buffering;
328
329 template <typename OutputIterator, typename Properties
330 , typename Derived = unused_type>
331 class output_iterator;
332
333 ///////////////////////////////////////////////////////////////////////////
334 template <typename Buffering, typename Counting, typename Tracking>
335 struct output_iterator_base : Buffering, Counting, Tracking
336 {
337 typedef Buffering buffering_policy;
338 typedef Counting counting_policy;
339 typedef Tracking tracking_policy;
340
341 output_iterator_base() {}
342 output_iterator_base(output_iterator_base const& rhs)
343 : buffering_policy(rhs), counting_policy(rhs), tracking_policy(rhs)
344 {}
345
346 template <typename T>
347 bool output(T const& value)
348 {
349 this->counting_policy::output(value);
350 this->tracking_policy::output(value);
351 return this->buffering_policy::output(value);
352 }
353 };
354
355 template <typename Buffering, typename Counting, typename Tracking>
356 struct disabling_output_iterator : Buffering, Counting, Tracking
357 {
358 typedef Buffering buffering_policy;
359 typedef Counting counting_policy;
360 typedef Tracking tracking_policy;
361
362 disabling_output_iterator() : do_output(true) {}
363 disabling_output_iterator(disabling_output_iterator const& rhs)
364 : buffering_policy(rhs), counting_policy(rhs), tracking_policy(rhs)
365 , do_output(rhs.do_output)
366 {}
367
368 template <typename T>
369 bool output(T const& value)
370 {
371 if (!do_output)
372 return false;
373
374 this->counting_policy::output(value);
375 this->tracking_policy::output(value);
376 return this->buffering_policy::output(value);
377 }
378
379 bool do_output;
380 };
381
382 ///////////////////////////////////////////////////////////////////////////
383 template <typename OutputIterator, typename Properties, typename Derived>
384 struct make_output_iterator
385 {
386 // get the most derived type of this class
387 typedef typename mpl::if_<
388 traits::not_is_unused<Derived>, Derived
389 , output_iterator<OutputIterator, Properties, Derived>
390 >::type most_derived_type;
391
392 static const generator_properties::enum_type properties = static_cast<generator_properties::enum_type>(Properties::value);
393
394 typedef typename mpl::if_c<
395 (properties & generator_properties::tracking) ? true : false
396 , position_policy, no_position_policy
397 >::type tracking_type;
398
399 typedef typename mpl::if_c<
400 (properties & generator_properties::buffering) ? true : false
401 , buffering_policy, no_buffering_policy
402 >::type buffering_type;
403
404 typedef typename mpl::if_c<
405 (properties & generator_properties::counting) ? true : false
406 , counting_policy<most_derived_type>, no_counting_policy
407 >::type counting_type;
408
409 typedef typename mpl::if_c<
410 (properties & generator_properties::disabling) ? true : false
411 , disabling_output_iterator<buffering_type, counting_type, tracking_type>
412 , output_iterator_base<buffering_type, counting_type, tracking_type>
413 >::type type;
414 };
415
416 ///////////////////////////////////////////////////////////////////////////
417 // Karma uses an output iterator wrapper for all output operations. This
418 // is necessary to avoid the dreaded 'scanner business' problem, i.e. the
419 // dependency of rules and grammars on the used output iterator.
420 //
421 // By default the user supplied output iterator is wrapped inside an
422 // instance of this internal output_iterator class.
423 //
424 // This output_iterator class normally just forwards to the embedded user
425 // supplied iterator. But it is possible to enable additional functionality
426 // on demand, such as counting, buffering, and position tracking.
427 ///////////////////////////////////////////////////////////////////////////
428 template <typename OutputIterator, typename Properties, typename Derived>
429 class output_iterator
430 : public make_output_iterator<OutputIterator, Properties, Derived>::type
431 {
432 private:
433 // base iterator type
434 typedef typename make_output_iterator<
435 OutputIterator, Properties, Derived>::type base_iterator;
436
437 public:
438 typedef std::output_iterator_tag iterator_category;
439 typedef void value_type;
440 typedef void difference_type;
441 typedef void pointer;
442 typedef void reference;
443
444 explicit output_iterator(OutputIterator& sink_)
445 : sink(&sink_)
446 {}
447 output_iterator(output_iterator const& rhs)
448 : base_iterator(rhs), sink(rhs.sink)
449 {}
450
451 output_iterator& operator*() { return *this; }
452 output_iterator& operator++()
453 {
454 if (!this->base_iterator::has_buffer())
455 ++(*sink); // increment only if not buffering
456 return *this;
457 }
458 output_iterator operator++(int)
459 {
460 if (!this->base_iterator::has_buffer()) {
461 output_iterator t(*this);
462 ++(*sink);
463 return t;
464 }
465 return *this;
466 }
467
468#if defined(BOOST_MSVC)
469// 'argument' : conversion from '...' to '...', possible loss of data
470#pragma warning (push)
471#pragma warning (disable: 4244)
472#endif
473 template <typename T>
474 void operator=(T const& value)
475 {
476 if (this->base_iterator::output(value))
477 *(*sink) = value;
478 }
479#if defined(BOOST_MSVC)
480#pragma warning (pop)
481#endif
482
483 // plain output iterators are considered to be good all the time
484 bool good() const { return true; }
485
486 // allow to access underlying output iterator
487 OutputIterator& base() { return *sink; }
488
489 protected:
490 // this is the wrapped user supplied output iterator
491 OutputIterator* sink;
492 };
493
494 ///////////////////////////////////////////////////////////////////////////
495 template <typename T, typename Elem, typename Traits, typename Properties>
496 class output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties>
497 : public output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties
498 , output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties> >
499 {
500 private:
501 typedef output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties
502 , output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties>
503 > base_type;
504 typedef karma::ostream_iterator<T, Elem, Traits> base_iterator_type;
505 typedef std::basic_ostream<Elem, Traits> ostream_type;
506
507 public:
508 output_iterator(base_iterator_type& sink)
509 : base_type(sink) {}
510
511 ostream_type& get_ostream() { return (*this->sink).get_ostream(); }
512 ostream_type const& get_ostream() const { return (*this->sink).get_ostream(); }
513
514 // expose good bit of underlying stream object
515 bool good() const { return (*this->sink).get_ostream().good(); }
516 };
517
518 ///////////////////////////////////////////////////////////////////////////
519 // Helper class for exception safe enabling of character counting in the
520 // output iterator
521 ///////////////////////////////////////////////////////////////////////////
522 template <typename OutputIterator>
523 struct enable_counting
524 {
525 enable_counting(OutputIterator& sink_, std::size_t count = 0)
526 : count_data(sink_, count) {}
527
528 // get number of characters counted since last enable
529 std::size_t count() const
530 {
531 return count_data.get_count();
532 }
533
534 private:
535 counting_sink<OutputIterator> count_data; // for counting
536 };
537
538 template <typename OutputIterator>
539 struct disable_counting
540 {
541 disable_counting(OutputIterator& sink_)
542 : count_data(sink_, 0, false) {}
543
544 private:
545 counting_sink<OutputIterator> count_data;
546 };
547
548 ///////////////////////////////////////////////////////////////////////////
549 // Helper class for exception safe enabling of character buffering in the
550 // output iterator
551 ///////////////////////////////////////////////////////////////////////////
552 template <typename OutputIterator>
553 struct enable_buffering
554 {
555 enable_buffering(OutputIterator& sink_
556 , std::size_t width = std::size_t(-1))
557 : sink(sink_), prev_buffer(NULL), enabled(false)
558 {
559 buffer_data.enable(width_: width);
560 prev_buffer = sink.chain_buffering(&buffer_data);
561 enabled = true;
562 }
563 ~enable_buffering()
564 {
565 disable();
566 }
567
568 // reset buffer chain to initial state
569 void disable()
570 {
571 if (enabled) {
572 BOOST_VERIFY(&buffer_data == sink.chain_buffering(prev_buffer));
573 enabled = false;
574 }
575 }
576
577 // copy to the underlying sink whatever is in the local buffer
578 bool buffer_copy(std::size_t maxwidth = std::size_t(-1)
579 , bool disable_ = true)
580 {
581 if (disable_)
582 disable();
583 return buffer_data.copy(sink, maxwidth) && sink.good();
584 }
585
586 // return number of characters stored in the buffer
587 std::size_t buffer_size() const
588 {
589 return buffer_data.buffer_size();
590 }
591
592 // copy to the remaining characters to the specified sink
593 template <typename RestIterator>
594 bool buffer_copy_rest(RestIterator& sink, std::size_t start_at = 0) const
595 {
596 return buffer_data.copy_rest(sink, start_at);
597 }
598
599 // copy the contents to the given output iterator
600 template <typename OutputIterator_>
601 bool buffer_copy_to(OutputIterator_& sink
602 , std::size_t maxwidth = std::size_t(-1)) const
603 {
604 return buffer_data.copy(sink, maxwidth);
605 }
606
607 private:
608 OutputIterator& sink;
609 buffer_sink buffer_data; // for buffering
610 buffer_sink* prev_buffer; // previous buffer in chain
611 bool enabled;
612 };
613
614 ///////////////////////////////////////////////////////////////////////////
615 // Helper class for exception safe disabling of output
616 ///////////////////////////////////////////////////////////////////////////
617 template <typename OutputIterator>
618 struct disable_output
619 {
620 disable_output(OutputIterator& sink_)
621 : sink(sink_), prev_do_output(sink.do_output)
622 {
623 sink.do_output = false;
624 }
625 ~disable_output()
626 {
627 sink.do_output = prev_do_output;
628 }
629
630 OutputIterator& sink;
631 bool prev_do_output;
632 };
633
634 ///////////////////////////////////////////////////////////////////////////
635 template <typename Sink>
636 bool sink_is_good(Sink const&)
637 {
638 return true; // the general case is always good
639 }
640
641 template <typename OutputIterator, typename Derived>
642 bool sink_is_good(output_iterator<OutputIterator, Derived> const& sink)
643 {
644 return sink.good(); // our own output iterators are handled separately
645 }
646
647}}}}
648
649#endif
650
651

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