]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
29 | namespace 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(BOOST_MSVC) && 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(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(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)(buffer.size(), maxwidth); | |
238 | ||
239 | #if defined(BOOST_MSVC) | |
240 | #pragma warning(pop) | |
241 | #endif | |
242 | std::copy(buffer.begin(), end, sink); | |
243 | return true; | |
244 | } | |
245 | template <typename RestIterator> | |
246 | bool copy_rest(RestIterator& sink, std::size_t start_at) const | |
247 | { | |
248 | #if defined(BOOST_MSVC) | |
249 | #pragma warning(push) | |
250 | #pragma warning(disable: 4267) | |
251 | #endif | |
252 | typename std::basic_string<buffer_char_type>::const_iterator begin = | |
253 | buffer.begin() + (std::min)(buffer.size(), start_at); | |
254 | ||
255 | #if defined(BOOST_MSVC) | |
256 | #pragma warning(pop) | |
257 | #endif | |
258 | std::copy(begin, buffer.end(), sink); | |
259 | return true; | |
260 | } | |
261 | ||
262 | std::size_t buffer_size() const | |
263 | { | |
264 | return buffer.size(); | |
265 | } | |
266 | ||
267 | private: | |
268 | std::size_t width; | |
269 | std::basic_string<buffer_char_type> buffer; | |
270 | }; | |
271 | ||
272 | /////////////////////////////////////////////////////////////////////////// | |
273 | struct buffering_policy | |
274 | { | |
275 | public: | |
276 | buffering_policy() : buffer(NULL) {} | |
277 | buffering_policy(buffering_policy const& rhs) : buffer(rhs.buffer) {} | |
278 | ||
279 | // functions related to buffering | |
280 | buffer_sink* chain_buffering(buffer_sink* buffer_data) | |
281 | { | |
282 | buffer_sink* prev_buffer = buffer; | |
283 | buffer = buffer_data; | |
284 | return prev_buffer; | |
285 | } | |
286 | ||
287 | template <typename T> | |
288 | bool output(T const& value) | |
289 | { | |
290 | // buffer characters, if appropriate | |
291 | if (NULL != buffer) { | |
292 | buffer->output(value); | |
293 | return false; | |
294 | } | |
295 | return true; | |
296 | } | |
297 | ||
298 | bool has_buffer() const { return NULL != buffer; } | |
299 | ||
300 | private: | |
301 | buffer_sink* buffer; | |
302 | }; | |
303 | ||
304 | struct no_buffering_policy | |
305 | { | |
306 | no_buffering_policy() {} | |
307 | no_buffering_policy(no_counting_policy const&) {} | |
308 | ||
309 | template <typename T> | |
310 | bool output(T const& /*value*/) | |
311 | { | |
312 | return true; | |
313 | } | |
314 | ||
315 | bool has_buffer() const { return false; } | |
316 | }; | |
317 | ||
318 | /////////////////////////////////////////////////////////////////////////// | |
319 | // forward declaration only | |
320 | template <typename OutputIterator> | |
321 | struct enable_buffering; | |
322 | ||
323 | template <typename OutputIterator, typename Properties | |
324 | , typename Derived = unused_type> | |
325 | class output_iterator; | |
326 | ||
327 | /////////////////////////////////////////////////////////////////////////// | |
328 | template <typename Buffering, typename Counting, typename Tracking> | |
329 | struct output_iterator_base : Buffering, Counting, Tracking | |
330 | { | |
331 | typedef Buffering buffering_policy; | |
332 | typedef Counting counting_policy; | |
333 | typedef Tracking tracking_policy; | |
334 | ||
335 | output_iterator_base() {} | |
336 | output_iterator_base(output_iterator_base const& rhs) | |
337 | : buffering_policy(rhs), counting_policy(rhs), tracking_policy(rhs) | |
338 | {} | |
339 | ||
340 | template <typename T> | |
341 | bool output(T const& value) | |
342 | { | |
343 | this->counting_policy::output(value); | |
344 | this->tracking_policy::output(value); | |
345 | return this->buffering_policy::output(value); | |
346 | } | |
347 | }; | |
348 | ||
349 | template <typename Buffering, typename Counting, typename Tracking> | |
350 | struct disabling_output_iterator : Buffering, Counting, Tracking | |
351 | { | |
352 | typedef Buffering buffering_policy; | |
353 | typedef Counting counting_policy; | |
354 | typedef Tracking tracking_policy; | |
355 | ||
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) | |
360 | {} | |
361 | ||
362 | template <typename T> | |
363 | bool output(T const& value) | |
364 | { | |
365 | if (!do_output) | |
366 | return false; | |
367 | ||
368 | this->counting_policy::output(value); | |
369 | this->tracking_policy::output(value); | |
370 | return this->buffering_policy::output(value); | |
371 | } | |
372 | ||
373 | bool do_output; | |
374 | }; | |
375 | ||
376 | /////////////////////////////////////////////////////////////////////////// | |
377 | template <typename OutputIterator, typename Properties, typename Derived> | |
378 | struct make_output_iterator | |
379 | { | |
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; | |
385 | ||
386 | enum { properties = Properties::value }; | |
387 | ||
388 | typedef typename mpl::if_c< | |
389 | (properties & generator_properties::tracking) ? true : false | |
390 | , position_policy, no_position_policy | |
391 | >::type tracking_type; | |
392 | ||
393 | typedef typename mpl::if_c< | |
394 | (properties & generator_properties::buffering) ? true : false | |
395 | , buffering_policy, no_buffering_policy | |
396 | >::type buffering_type; | |
397 | ||
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; | |
402 | ||
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> | |
407 | >::type type; | |
408 | }; | |
409 | ||
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. | |
414 | // | |
415 | // By default the user supplied output iterator is wrapped inside an | |
416 | // instance of this internal output_iterator class. | |
417 | // | |
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 | |
425 | { | |
426 | private: | |
427 | // base iterator type | |
428 | typedef typename make_output_iterator< | |
429 | OutputIterator, Properties, Derived>::type base_iterator; | |
430 | ||
431 | public: | |
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; | |
437 | ||
438 | explicit output_iterator(OutputIterator& sink_) | |
439 | : sink(&sink_) | |
440 | {} | |
441 | output_iterator(output_iterator const& rhs) | |
442 | : base_iterator(rhs), sink(rhs.sink) | |
443 | {} | |
444 | ||
445 | output_iterator& operator*() { return *this; } | |
446 | output_iterator& operator++() | |
447 | { | |
448 | if (!this->base_iterator::has_buffer()) | |
449 | ++(*sink); // increment only if not buffering | |
450 | return *this; | |
451 | } | |
452 | output_iterator operator++(int) | |
453 | { | |
454 | if (!this->base_iterator::has_buffer()) { | |
455 | output_iterator t(*this); | |
456 | ++(*sink); | |
457 | return t; | |
458 | } | |
459 | return *this; | |
460 | } | |
461 | ||
462 | #if defined(BOOST_MSVC) | |
463 | // 'argument' : conversion from '...' to '...', possible loss of data | |
464 | #pragma warning (push) | |
465 | #pragma warning (disable: 4244) | |
466 | #endif | |
467 | template <typename T> | |
468 | void operator=(T const& value) | |
469 | { | |
470 | if (this->base_iterator::output(value)) | |
471 | *(*sink) = value; | |
472 | } | |
473 | #if defined(BOOST_MSVC) | |
474 | #pragma warning (pop) | |
475 | #endif | |
476 | ||
477 | // plain output iterators are considered to be good all the time | |
478 | bool good() const { return true; } | |
479 | ||
480 | // allow to access underlying output iterator | |
481 | OutputIterator& base() { return *sink; } | |
482 | ||
483 | protected: | |
484 | // this is the wrapped user supplied output iterator | |
485 | OutputIterator* sink; | |
486 | }; | |
487 | ||
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> > | |
493 | { | |
494 | private: | |
495 | typedef output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties | |
496 | , output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties> | |
497 | > base_type; | |
498 | typedef karma::ostream_iterator<T, Elem, Traits> base_iterator_type; | |
499 | typedef std::basic_ostream<Elem, Traits> ostream_type; | |
500 | ||
501 | public: | |
502 | output_iterator(base_iterator_type& sink) | |
503 | : base_type(sink) {} | |
504 | ||
505 | ostream_type& get_ostream() { return (*this->sink).get_ostream(); } | |
506 | ostream_type const& get_ostream() const { return (*this->sink).get_ostream(); } | |
507 | ||
508 | // expose good bit of underlying stream object | |
509 | bool good() const { return (*this->sink).get_ostream().good(); } | |
510 | }; | |
511 | ||
512 | /////////////////////////////////////////////////////////////////////////// | |
513 | // Helper class for exception safe enabling of character counting in the | |
514 | // output iterator | |
515 | /////////////////////////////////////////////////////////////////////////// | |
516 | template <typename OutputIterator> | |
517 | struct enable_counting | |
518 | { | |
519 | enable_counting(OutputIterator& sink_, std::size_t count = 0) | |
520 | : count_data(sink_, count) {} | |
521 | ||
522 | // get number of characters counted since last enable | |
523 | std::size_t count() const | |
524 | { | |
525 | return count_data.get_count(); | |
526 | } | |
527 | ||
528 | private: | |
529 | counting_sink<OutputIterator> count_data; // for counting | |
530 | }; | |
531 | ||
532 | template <typename OutputIterator> | |
533 | struct disable_counting | |
534 | { | |
535 | disable_counting(OutputIterator& sink_) | |
536 | : count_data(sink_, 0, false) {} | |
537 | ||
538 | private: | |
539 | counting_sink<OutputIterator> count_data; | |
540 | }; | |
541 | ||
542 | /////////////////////////////////////////////////////////////////////////// | |
543 | // Helper class for exception safe enabling of character buffering in the | |
544 | // output iterator | |
545 | /////////////////////////////////////////////////////////////////////////// | |
546 | template <typename OutputIterator> | |
547 | struct enable_buffering | |
548 | { | |
549 | enable_buffering(OutputIterator& sink_ | |
550 | , std::size_t width = std::size_t(-1)) | |
551 | : sink(sink_), prev_buffer(NULL), enabled(false) | |
552 | { | |
553 | buffer_data.enable(width); | |
554 | prev_buffer = sink.chain_buffering(&buffer_data); | |
555 | enabled = true; | |
556 | } | |
557 | ~enable_buffering() | |
558 | { | |
559 | disable(); | |
560 | } | |
561 | ||
562 | // reset buffer chain to initial state | |
563 | void disable() | |
564 | { | |
565 | if (enabled) { | |
566 | BOOST_VERIFY(&buffer_data == sink.chain_buffering(prev_buffer)); | |
567 | enabled = false; | |
568 | } | |
569 | } | |
570 | ||
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) | |
574 | { | |
575 | if (disable_) | |
576 | disable(); | |
577 | return buffer_data.copy(sink, maxwidth) && sink.good(); | |
578 | } | |
579 | ||
580 | // return number of characters stored in the buffer | |
581 | std::size_t buffer_size() const | |
582 | { | |
583 | return buffer_data.buffer_size(); | |
584 | } | |
585 | ||
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 | |
589 | { | |
590 | return buffer_data.copy_rest(sink, start_at); | |
591 | } | |
592 | ||
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 | |
597 | { | |
598 | return buffer_data.copy(sink, maxwidth); | |
599 | } | |
600 | ||
601 | private: | |
602 | OutputIterator& sink; | |
603 | buffer_sink buffer_data; // for buffering | |
604 | buffer_sink* prev_buffer; // previous buffer in chain | |
605 | bool enabled; | |
606 | }; | |
607 | ||
608 | /////////////////////////////////////////////////////////////////////////// | |
609 | // Helper class for exception safe disabling of output | |
610 | /////////////////////////////////////////////////////////////////////////// | |
611 | template <typename OutputIterator> | |
612 | struct disable_output | |
613 | { | |
614 | disable_output(OutputIterator& sink_) | |
615 | : sink(sink_), prev_do_output(sink.do_output) | |
616 | { | |
617 | sink.do_output = false; | |
618 | } | |
619 | ~disable_output() | |
620 | { | |
621 | sink.do_output = prev_do_output; | |
622 | } | |
623 | ||
624 | OutputIterator& sink; | |
625 | bool prev_do_output; | |
626 | }; | |
627 | ||
628 | /////////////////////////////////////////////////////////////////////////// | |
629 | template <typename Sink> | |
630 | bool sink_is_good(Sink const&) | |
631 | { | |
632 | return true; // the general case is always good | |
633 | } | |
634 | ||
635 | template <typename OutputIterator, typename Derived> | |
636 | bool sink_is_good(output_iterator<OutputIterator, Derived> const& sink) | |
637 | { | |
638 | return sink.good(); // our own output iterators are handled separately | |
639 | } | |
640 | ||
641 | }}}} | |
642 | ||
643 | #endif | |
644 |