PageRenderTime 52ms CodeModel.GetById 2ms app.highlight 44ms RepoModel.GetById 1ms app.codeStats 1ms

/Src/Dependencies/Boost/boost/spirit/home/karma/detail/output_iterator.hpp

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