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_OUTPUT_ITERATOR_MAY_26_2007_0506PM)
7 #define BOOST_SPIRIT_KARMA_OUTPUT_ITERATOR_MAY_26_2007_0506PM
17 #include <boost/config.hpp>
18 #include <boost/noncopyable.hpp>
19 #include <boost/mpl/if.hpp>
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>
25 #if defined(BOOST_MSVC) && defined(BOOST_SPIRIT_UNICODE)
26 #include <boost/spirit/home/support/char_encoding/unicode.hpp>
29 namespace boost { namespace spirit { namespace karma { namespace detail
31 ///////////////////////////////////////////////////////////////////////////
32 // This class is used to keep track of the current position in the output.
33 ///////////////////////////////////////////////////////////////////////////
37 position_sink() : count(0), line(1), column(1) {}
38 void tidy() { count = 0; line = 1; column = 1; }
41 void output(T const& value)
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; }
62 ///////////////////////////////////////////////////////////////////////////
63 struct position_policy
66 position_policy(position_policy const& rhs)
67 : track_position_data(rhs.track_position_data) {}
70 void output(T const& value)
72 // track position in the output
73 track_position_data.output(value);
76 // return the current count in the output
77 std::size_t get_out_count() const
79 return track_position_data.get_count();
82 // return the current line in the output
83 std::size_t get_line() const
85 return track_position_data.get_line();
88 // return the current column in the output
89 std::size_t get_column() const
91 return track_position_data.get_column();
95 position_sink track_position_data; // for position tracking
98 struct no_position_policy
100 no_position_policy() {}
101 no_position_policy(no_position_policy const&) {}
103 template <typename T>
104 void output(T const& /*value*/) {}
107 ///////////////////////////////////////////////////////////////////////////
108 // This class is used to count the number of characters streamed into the
110 ///////////////////////////////////////////////////////////////////////////
111 template <typename OutputIterator>
112 class counting_sink : boost::noncopyable
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_)
119 prev_count = sink.chain_counting(enabled ? this : NULL);
123 if (prev_count) // propagate count
124 prev_count->update_count(count-initial_count);
125 sink.chain_counting(prev_count);
132 std::size_t get_count() const { return count; }
134 // propagate count from embedded counters
135 void update_count(std::size_t c)
142 std::size_t initial_count;
143 counting_sink* prev_count; // previous counter in chain
144 OutputIterator& sink;
147 ///////////////////////////////////////////////////////////////////////////
148 template <typename OutputIterator>
149 struct counting_policy
152 counting_policy() : count(NULL) {}
153 counting_policy(counting_policy const& rhs) : count(rhs.count) {}
155 // functions related to counting
156 counting_sink<OutputIterator>* chain_counting(
157 counting_sink<OutputIterator>* count_data)
159 counting_sink<OutputIterator>* prev_count = count;
164 template <typename T>
165 void output(T const&)
167 // count characters, if appropriate
173 counting_sink<OutputIterator>* count; // for counting
176 struct no_counting_policy
178 no_counting_policy() {}
179 no_counting_policy(no_counting_policy const&) {}
181 template <typename T>
182 void output(T const& /*value*/) {}
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
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(BOOST_MSVC) && defined(BOOST_SPIRIT_UNICODE)
195 typedef spirit::char_encoding::unicode::char_type buffer_char_type;
197 typedef wchar_t buffer_char_type;
209 void enable(std::size_t width_)
211 tidy(); // release existing buffer
212 width = (width_ == std::size_t(-1)) ? 0 : width_;
213 buffer.reserve(width);
222 template <typename T>
223 void output(T const& value)
225 BOOST_STATIC_ASSERT(sizeof(T) <= sizeof(buffer_char_type));
226 buffer.push_back(value);
229 template <typename OutputIterator_>
230 bool copy(OutputIterator_& sink, std::size_t maxwidth) const
232 #if defined(BOOST_MSVC)
233 #pragma warning(push)
234 #pragma warning(disable: 4267)
236 typename std::basic_string<buffer_char_type>::const_iterator end =
237 buffer.begin() + (std::min)(buffer.size(), maxwidth);
239 #if defined(BOOST_MSVC)
242 std::copy(buffer.begin(), end, sink);
245 template <typename RestIterator>
246 bool copy_rest(RestIterator& sink, std::size_t start_at) const
248 #if defined(BOOST_MSVC)
249 #pragma warning(push)
250 #pragma warning(disable: 4267)
252 typename std::basic_string<buffer_char_type>::const_iterator begin =
253 buffer.begin() + (std::min)(buffer.size(), start_at);
255 #if defined(BOOST_MSVC)
258 std::copy(begin, buffer.end(), sink);
262 std::size_t buffer_size() const
264 return buffer.size();
269 std::basic_string<buffer_char_type> buffer;
272 ///////////////////////////////////////////////////////////////////////////
273 struct buffering_policy
276 buffering_policy() : buffer(NULL) {}
277 buffering_policy(buffering_policy const& rhs) : buffer(rhs.buffer) {}
279 // functions related to buffering
280 buffer_sink* chain_buffering(buffer_sink* buffer_data)
282 buffer_sink* prev_buffer = buffer;
283 buffer = buffer_data;
287 template <typename T>
288 bool output(T const& value)
290 // buffer characters, if appropriate
291 if (NULL != buffer) {
292 buffer->output(value);
298 bool has_buffer() const { return NULL != buffer; }
304 struct no_buffering_policy
306 no_buffering_policy() {}
307 no_buffering_policy(no_counting_policy const&) {}
309 template <typename T>
310 bool output(T const& /*value*/)
315 bool has_buffer() const { return false; }
318 ///////////////////////////////////////////////////////////////////////////
319 // forward declaration only
320 template <typename OutputIterator>
321 struct enable_buffering;
323 template <typename OutputIterator, typename Properties
324 , typename Derived = unused_type>
325 class output_iterator;
327 ///////////////////////////////////////////////////////////////////////////
328 template <typename Buffering, typename Counting, typename Tracking>
329 struct output_iterator_base : Buffering, Counting, Tracking
331 typedef Buffering buffering_policy;
332 typedef Counting counting_policy;
333 typedef Tracking tracking_policy;
335 output_iterator_base() {}
336 output_iterator_base(output_iterator_base const& rhs)
337 : buffering_policy(rhs), counting_policy(rhs), tracking_policy(rhs)
340 template <typename T>
341 bool output(T const& value)
343 this->counting_policy::output(value);
344 this->tracking_policy::output(value);
345 return this->buffering_policy::output(value);
349 template <typename Buffering, typename Counting, typename Tracking>
350 struct disabling_output_iterator : Buffering, Counting, Tracking
352 typedef Buffering buffering_policy;
353 typedef Counting counting_policy;
354 typedef Tracking tracking_policy;
356 disabling_output_iterator() : do_output(true) {}
357 disabling_output_iterator(disabling_output_iterator const& rhs)
358 : buffering_policy(rhs), counting_policy(rhs), tracking_policy(rhs)
359 , do_output(rhs.do_output)
362 template <typename T>
363 bool output(T const& value)
368 this->counting_policy::output(value);
369 this->tracking_policy::output(value);
370 return this->buffering_policy::output(value);
376 ///////////////////////////////////////////////////////////////////////////
377 template <typename OutputIterator, typename Properties, typename Derived>
378 struct make_output_iterator
380 // get the most derived type of this class
381 typedef typename mpl::if_<
382 traits::not_is_unused<Derived>, Derived
383 , output_iterator<OutputIterator, Properties, Derived>
384 >::type most_derived_type;
386 enum { properties = Properties::value };
388 typedef typename mpl::if_c<
389 (properties & generator_properties::tracking) ? true : false
390 , position_policy, no_position_policy
391 >::type tracking_type;
393 typedef typename mpl::if_c<
394 (properties & generator_properties::buffering) ? true : false
395 , buffering_policy, no_buffering_policy
396 >::type buffering_type;
398 typedef typename mpl::if_c<
399 (properties & generator_properties::counting) ? true : false
400 , counting_policy<most_derived_type>, no_counting_policy
401 >::type counting_type;
403 typedef typename mpl::if_c<
404 (properties & generator_properties::disabling) ? true : false
405 , disabling_output_iterator<buffering_type, counting_type, tracking_type>
406 , output_iterator_base<buffering_type, counting_type, tracking_type>
410 ///////////////////////////////////////////////////////////////////////////
411 // Karma uses an output iterator wrapper for all output operations. This
412 // is necessary to avoid the dreaded 'scanner business' problem, i.e. the
413 // dependency of rules and grammars on the used output iterator.
415 // By default the user supplied output iterator is wrapped inside an
416 // instance of this internal output_iterator class.
418 // This output_iterator class normally just forwards to the embedded user
419 // supplied iterator. But it is possible to enable additional functionality
420 // on demand, such as counting, buffering, and position tracking.
421 ///////////////////////////////////////////////////////////////////////////
422 template <typename OutputIterator, typename Properties, typename Derived>
423 class output_iterator
424 : public make_output_iterator<OutputIterator, Properties, Derived>::type
427 // base iterator type
428 typedef typename make_output_iterator<
429 OutputIterator, Properties, Derived>::type base_iterator;
432 typedef std::output_iterator_tag iterator_category;
433 typedef void value_type;
434 typedef void difference_type;
435 typedef void pointer;
436 typedef void reference;
438 explicit output_iterator(OutputIterator& sink_)
441 output_iterator(output_iterator const& rhs)
442 : base_iterator(rhs), sink(rhs.sink)
445 output_iterator& operator*() { return *this; }
446 output_iterator& operator++()
448 if (!this->base_iterator::has_buffer())
449 ++(*sink); // increment only if not buffering
452 output_iterator operator++(int)
454 if (!this->base_iterator::has_buffer()) {
455 output_iterator t(*this);
462 #if defined(BOOST_MSVC)
463 // 'argument' : conversion from '...' to '...', possible loss of data
464 #pragma warning (push)
465 #pragma warning (disable: 4244)
467 template <typename T>
468 void operator=(T const& value)
470 if (this->base_iterator::output(value))
473 #if defined(BOOST_MSVC)
474 #pragma warning (pop)
477 // plain output iterators are considered to be good all the time
478 bool good() const { return true; }
480 // allow to access underlying output iterator
481 OutputIterator& base() { return *sink; }
484 // this is the wrapped user supplied output iterator
485 OutputIterator* sink;
488 ///////////////////////////////////////////////////////////////////////////
489 template <typename T, typename Elem, typename Traits, typename Properties>
490 class output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties>
491 : public output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties
492 , output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties> >
495 typedef output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties
496 , output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties>
498 typedef karma::ostream_iterator<T, Elem, Traits> base_iterator_type;
499 typedef std::basic_ostream<Elem, Traits> ostream_type;
502 output_iterator(base_iterator_type& sink)
505 ostream_type& get_ostream() { return (*this->sink).get_ostream(); }
506 ostream_type const& get_ostream() const { return (*this->sink).get_ostream(); }
508 // expose good bit of underlying stream object
509 bool good() const { return (*this->sink).get_ostream().good(); }
512 ///////////////////////////////////////////////////////////////////////////
513 // Helper class for exception safe enabling of character counting in the
515 ///////////////////////////////////////////////////////////////////////////
516 template <typename OutputIterator>
517 struct enable_counting
519 enable_counting(OutputIterator& sink_, std::size_t count = 0)
520 : count_data(sink_, count) {}
522 // get number of characters counted since last enable
523 std::size_t count() const
525 return count_data.get_count();
529 counting_sink<OutputIterator> count_data; // for counting
532 template <typename OutputIterator>
533 struct disable_counting
535 disable_counting(OutputIterator& sink_)
536 : count_data(sink_, 0, false) {}
539 counting_sink<OutputIterator> count_data;
542 ///////////////////////////////////////////////////////////////////////////
543 // Helper class for exception safe enabling of character buffering in the
545 ///////////////////////////////////////////////////////////////////////////
546 template <typename OutputIterator>
547 struct enable_buffering
549 enable_buffering(OutputIterator& sink_
550 , std::size_t width = std::size_t(-1))
551 : sink(sink_), prev_buffer(NULL), enabled(false)
553 buffer_data.enable(width);
554 prev_buffer = sink.chain_buffering(&buffer_data);
562 // reset buffer chain to initial state
566 BOOST_VERIFY(&buffer_data == sink.chain_buffering(prev_buffer));
571 // copy to the underlying sink whatever is in the local buffer
572 bool buffer_copy(std::size_t maxwidth = std::size_t(-1)
573 , bool disable_ = true)
577 return buffer_data.copy(sink, maxwidth) && sink.good();
580 // return number of characters stored in the buffer
581 std::size_t buffer_size() const
583 return buffer_data.buffer_size();
586 // copy to the remaining characters to the specified sink
587 template <typename RestIterator>
588 bool buffer_copy_rest(RestIterator& sink, std::size_t start_at = 0) const
590 return buffer_data.copy_rest(sink, start_at);
593 // copy the contents to the given output iterator
594 template <typename OutputIterator_>
595 bool buffer_copy_to(OutputIterator_& sink
596 , std::size_t maxwidth = std::size_t(-1)) const
598 return buffer_data.copy(sink, maxwidth);
602 OutputIterator& sink;
603 buffer_sink buffer_data; // for buffering
604 buffer_sink* prev_buffer; // previous buffer in chain
608 ///////////////////////////////////////////////////////////////////////////
609 // Helper class for exception safe disabling of output
610 ///////////////////////////////////////////////////////////////////////////
611 template <typename OutputIterator>
612 struct disable_output
614 disable_output(OutputIterator& sink_)
615 : sink(sink_), prev_do_output(sink.do_output)
617 sink.do_output = false;
621 sink.do_output = prev_do_output;
624 OutputIterator& sink;
628 ///////////////////////////////////////////////////////////////////////////
629 template <typename Sink>
630 bool sink_is_good(Sink const&)
632 return true; // the general case is always good
635 template <typename OutputIterator, typename Derived>
636 bool sink_is_good(output_iterator<OutputIterator, Derived> const& sink)
638 return sink.good(); // our own output iterators are handled separately