Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-19 09:47:35

0001 //  Copyright (c) 2001-2011 Hartmut Kaiser
0002 // 
0003 //  Distributed under the Boost Software License, Version 1.0. (See accompanying 
0004 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0005 
0006 #if !defined(BOOST_SPIRIT_KARMA_OUTPUT_ITERATOR_MAY_26_2007_0506PM)
0007 #define BOOST_SPIRIT_KARMA_OUTPUT_ITERATOR_MAY_26_2007_0506PM
0008 
0009 #if defined(_MSC_VER)
0010 #pragma once
0011 #endif
0012 
0013 #include <iterator>
0014 #include <vector>
0015 #include <algorithm>
0016 
0017 #include <boost/config.hpp>
0018 #include <boost/noncopyable.hpp>
0019 #include <boost/mpl/if.hpp>
0020 
0021 #include <boost/spirit/home/karma/generator.hpp>
0022 #include <boost/spirit/home/support/iterators/ostream_iterator.hpp>
0023 #include <boost/spirit/home/support/unused.hpp>
0024 
0025 #if defined(BOOST_MSVC) && defined(BOOST_SPIRIT_UNICODE)
0026 #include <boost/spirit/home/support/char_encoding/unicode.hpp>
0027 #endif
0028 
0029 namespace boost { namespace spirit { namespace karma { namespace detail 
0030 {
0031     ///////////////////////////////////////////////////////////////////////////
0032     //  This class is used to keep track of the current position in the output.
0033     ///////////////////////////////////////////////////////////////////////////
0034     class position_sink 
0035     {
0036     public:
0037         position_sink() : count(0), line(1), column(1) {}
0038         void tidy() { count = 0; line = 1; column = 1; }
0039 
0040         template <typename T>
0041         void output(T const& value) 
0042         {
0043             ++count; 
0044             if (value == '\n') {
0045                 ++line;
0046                 column = 1;
0047             }
0048             else {
0049                 ++column;
0050             }
0051         }
0052         std::size_t get_count() const { return count; }
0053         std::size_t get_line() const { return line; }
0054         std::size_t get_column() const { return column; }
0055 
0056     private:
0057         std::size_t count;
0058         std::size_t line;
0059         std::size_t column;
0060     };
0061 
0062     ///////////////////////////////////////////////////////////////////////////
0063     struct position_policy
0064     {
0065         position_policy() {}
0066         position_policy(position_policy const& rhs) 
0067           : track_position_data(rhs.track_position_data) {}
0068 
0069         template <typename T>
0070         void output(T const& value) 
0071         {
0072             // track position in the output 
0073             track_position_data.output(value);
0074         }
0075 
0076         // return the current count in the output
0077         std::size_t get_out_count() const
0078         {
0079             return track_position_data.get_count();
0080         }
0081 
0082     // return the current line in the output
0083     std::size_t get_line() const
0084     {
0085         return track_position_data.get_line();
0086     }
0087 
0088     // return the current column in the output
0089     std::size_t get_column() const
0090     {
0091         return track_position_data.get_column();
0092     }
0093 
0094     private:
0095         position_sink track_position_data;            // for position tracking
0096     };
0097 
0098     struct no_position_policy
0099     {
0100         no_position_policy() {}
0101         no_position_policy(no_position_policy const&) {}
0102 
0103         template <typename T>
0104         void output(T const& /*value*/) {}
0105     };
0106 
0107     ///////////////////////////////////////////////////////////////////////////
0108     //  This class is used to count the number of characters streamed into the 
0109     //  output.
0110     ///////////////////////////////////////////////////////////////////////////
0111     template <typename OutputIterator>
0112     class counting_sink : boost::noncopyable
0113     {
0114     public:
0115         counting_sink(OutputIterator& sink_, std::size_t count_ = 0
0116               , bool enabled = true) 
0117           : count(count_), initial_count(count), prev_count(0), sink(sink_)
0118         {
0119             prev_count = sink.chain_counting(enabled ? this : NULL);
0120         }
0121         ~counting_sink() 
0122         {
0123             if (prev_count)           // propagate count 
0124                 prev_count->update_count(count-initial_count);
0125             sink.chain_counting(prev_count);
0126         }
0127 
0128         void output() 
0129         {
0130             ++count; 
0131         }
0132         std::size_t get_count() const { return count; }
0133 
0134         // propagate count from embedded counters
0135         void update_count(std::size_t c)
0136         {
0137             count += c;
0138         }
0139 
0140     private:
0141         std::size_t count;
0142         std::size_t initial_count;
0143         counting_sink* prev_count;                // previous counter in chain
0144         OutputIterator& sink;
0145     };
0146 
0147     ///////////////////////////////////////////////////////////////////////////
0148     template <typename OutputIterator>
0149     struct counting_policy
0150     {
0151     public:
0152         counting_policy() : count(NULL) {}
0153         counting_policy(counting_policy const& rhs) : count(rhs.count) {}
0154 
0155         // functions related to counting
0156         counting_sink<OutputIterator>* chain_counting(
0157             counting_sink<OutputIterator>* count_data)
0158         {
0159             counting_sink<OutputIterator>* prev_count = count;
0160             count = count_data;
0161             return prev_count;
0162         }
0163 
0164         template <typename T>
0165         void output(T const&) 
0166         {
0167             // count characters, if appropriate
0168             if (NULL != count)
0169                 count->output();
0170         }
0171 
0172     private:
0173         counting_sink<OutputIterator>* count;      // for counting
0174     };
0175 
0176     struct no_counting_policy
0177     {
0178         no_counting_policy() {}
0179         no_counting_policy(no_counting_policy const&) {}
0180 
0181         template <typename T>
0182         void output(T const& /*value*/) {}
0183     };
0184 
0185     ///////////////////////////////////////////////////////////////////////////
0186     //  The following classes are used to intercept the output into a buffer
0187     //  allowing to do things like alignment, character escaping etc.
0188     ///////////////////////////////////////////////////////////////////////////
0189     class buffer_sink : boost::noncopyable
0190     {
0191        // wchar_t is only 16-bits on Windows. If BOOST_SPIRIT_UNICODE is
0192        // defined, the character type is 32-bits wide so we need to make
0193        // sure the buffer is at least that wide.
0194 #if (defined(_MSC_VER) || defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) && defined(BOOST_SPIRIT_UNICODE)
0195        typedef spirit::char_encoding::unicode::char_type buffer_char_type;
0196 #else
0197        typedef wchar_t buffer_char_type;
0198 #endif
0199 
0200     public:
0201         buffer_sink()
0202           : width(0) {}
0203 
0204         ~buffer_sink() 
0205         {
0206             tidy(); 
0207         }
0208 
0209         void enable(std::size_t width_) 
0210         {
0211             tidy();             // release existing buffer
0212             width = (width_ == std::size_t(-1)) ? 0 : width_;
0213             buffer.reserve(width); 
0214         }
0215 
0216         void tidy() 
0217         {
0218             buffer.clear(); 
0219             width = 0; 
0220         }
0221 
0222         template <typename T>
0223         void output(T const& value)
0224         {
0225             BOOST_STATIC_ASSERT(sizeof(T) <= sizeof(buffer_char_type));
0226             buffer.push_back(value);
0227         }
0228 
0229         template <typename OutputIterator_>
0230         bool copy(OutputIterator_& sink, std::size_t maxwidth) const 
0231         {
0232 #if defined(BOOST_MSVC)
0233 #pragma warning(push)
0234 #pragma warning(disable: 4267)
0235 #endif
0236             typename std::basic_string<buffer_char_type>::const_iterator end = 
0237                 buffer.begin() + (std::min)(buffer.size(), maxwidth);
0238 
0239 #if defined(BOOST_MSVC)
0240 #pragma warning(disable: 4244) // conversion from 'x' to 'y', possible loss of data
0241 #endif
0242             std::copy(buffer.begin(), end, sink);
0243 #if defined(BOOST_MSVC)
0244 #pragma warning(pop)
0245 #endif
0246             return true;
0247         }
0248         template <typename RestIterator>
0249         bool copy_rest(RestIterator& sink, std::size_t start_at) const 
0250         {
0251 #if defined(BOOST_MSVC)
0252 #pragma warning(push)
0253 #pragma warning(disable: 4267)
0254 #endif
0255             typename std::basic_string<buffer_char_type>::const_iterator begin = 
0256                 buffer.begin() + (std::min)(buffer.size(), start_at);
0257 
0258 #if defined(BOOST_MSVC)
0259 #pragma warning(disable: 4244) // conversion from 'x' to 'y', possible loss of data
0260 #endif
0261             std::copy(begin, buffer.end(), sink);
0262 #if defined(BOOST_MSVC)
0263 #pragma warning(pop)
0264 #endif
0265             return true;
0266         }
0267 
0268         std::size_t buffer_size() const 
0269         {
0270             return buffer.size();
0271         }
0272 
0273     private:
0274         std::size_t width;
0275         std::basic_string<buffer_char_type> buffer;
0276     };
0277 
0278     ///////////////////////////////////////////////////////////////////////////
0279     struct buffering_policy
0280     {
0281     public:
0282         buffering_policy() : buffer(NULL) {}
0283         buffering_policy(buffering_policy const& rhs) : buffer(rhs.buffer) {}
0284 
0285         // functions related to buffering
0286         buffer_sink* chain_buffering(buffer_sink* buffer_data)
0287         {
0288             buffer_sink* prev_buffer = buffer;
0289             buffer = buffer_data;
0290             return prev_buffer;
0291         }
0292 
0293         template <typename T>
0294         bool output(T const& value) 
0295         { 
0296             // buffer characters, if appropriate
0297             if (NULL != buffer) {
0298                 buffer->output(value);
0299                 return false;
0300             }
0301             return true;
0302         }
0303 
0304         bool has_buffer() const { return NULL != buffer; }
0305 
0306     private:
0307         buffer_sink* buffer;
0308     };
0309 
0310     struct no_buffering_policy
0311     {
0312         no_buffering_policy() {}
0313         no_buffering_policy(no_buffering_policy const&) {}
0314 
0315         template <typename T>
0316         bool output(T const& /*value*/) 
0317         {
0318             return true;
0319         }
0320 
0321         bool has_buffer() const { return false; }
0322     };
0323 
0324     ///////////////////////////////////////////////////////////////////////////
0325     //  forward declaration only
0326     template <typename OutputIterator> 
0327     struct enable_buffering;
0328 
0329     template <typename OutputIterator, typename Properties
0330       , typename Derived = unused_type>
0331     class output_iterator;
0332 
0333     ///////////////////////////////////////////////////////////////////////////
0334     template <typename Buffering, typename Counting, typename Tracking>
0335     struct output_iterator_base : Buffering, Counting, Tracking
0336     {
0337         typedef Buffering buffering_policy;
0338         typedef Counting counting_policy;
0339         typedef Tracking tracking_policy;
0340 
0341         output_iterator_base() {}
0342         output_iterator_base(output_iterator_base const& rhs) 
0343           : buffering_policy(rhs), counting_policy(rhs), tracking_policy(rhs)
0344         {}
0345 
0346         template <typename T>
0347         bool output(T const& value) 
0348         { 
0349             this->counting_policy::output(value);
0350             this->tracking_policy::output(value);
0351             return this->buffering_policy::output(value);
0352         }
0353     };
0354 
0355     template <typename Buffering, typename Counting, typename Tracking>
0356     struct disabling_output_iterator : Buffering, Counting, Tracking
0357     {
0358         typedef Buffering buffering_policy;
0359         typedef Counting counting_policy;
0360         typedef Tracking tracking_policy;
0361 
0362         disabling_output_iterator() : do_output(true) {}
0363         disabling_output_iterator(disabling_output_iterator const& rhs) 
0364           : buffering_policy(rhs), counting_policy(rhs), tracking_policy(rhs)
0365           , do_output(rhs.do_output)
0366         {}
0367 
0368         template <typename T>
0369         bool output(T const& value) 
0370         { 
0371             if (!do_output) 
0372                 return false;
0373 
0374             this->counting_policy::output(value);
0375             this->tracking_policy::output(value);
0376             return this->buffering_policy::output(value);
0377         }
0378 
0379         bool do_output;
0380     };
0381 
0382     ///////////////////////////////////////////////////////////////////////////
0383     template <typename OutputIterator, typename Properties, typename Derived>
0384     struct make_output_iterator
0385     {
0386         // get the most derived type of this class
0387         typedef typename mpl::if_<
0388             traits::not_is_unused<Derived>, Derived
0389           , output_iterator<OutputIterator, Properties, Derived>
0390         >::type most_derived_type;
0391 
0392         static const generator_properties::enum_type properties = static_cast<generator_properties::enum_type>(Properties::value);
0393 
0394         typedef typename mpl::if_c<
0395             (properties & generator_properties::tracking) ? true : false
0396           , position_policy, no_position_policy
0397         >::type tracking_type;
0398 
0399         typedef typename mpl::if_c<
0400             (properties & generator_properties::buffering) ? true : false
0401           , buffering_policy, no_buffering_policy
0402         >::type buffering_type;
0403 
0404         typedef typename mpl::if_c<
0405             (properties & generator_properties::counting) ? true : false
0406           , counting_policy<most_derived_type>, no_counting_policy
0407         >::type counting_type;
0408 
0409         typedef typename mpl::if_c<
0410             (properties & generator_properties::disabling) ? true : false
0411           , disabling_output_iterator<buffering_type, counting_type, tracking_type>
0412           , output_iterator_base<buffering_type, counting_type, tracking_type>
0413         >::type type;
0414     };
0415 
0416     ///////////////////////////////////////////////////////////////////////////
0417     //  Karma uses an output iterator wrapper for all output operations. This
0418     //  is necessary to avoid the dreaded 'scanner business' problem, i.e. the
0419     //  dependency of rules and grammars on the used output iterator. 
0420     //
0421     //  By default the user supplied output iterator is wrapped inside an 
0422     //  instance of this internal output_iterator class. 
0423     //
0424     //  This output_iterator class normally just forwards to the embedded user
0425     //  supplied iterator. But it is possible to enable additional functionality
0426     //  on demand, such as counting, buffering, and position tracking.
0427     ///////////////////////////////////////////////////////////////////////////
0428     template <typename OutputIterator, typename Properties, typename Derived>
0429     class output_iterator 
0430       : public make_output_iterator<OutputIterator, Properties, Derived>::type
0431     {
0432     private:
0433         // base iterator type
0434         typedef typename make_output_iterator<
0435             OutputIterator, Properties, Derived>::type base_iterator;
0436 
0437     public:
0438         typedef std::output_iterator_tag iterator_category;
0439         typedef void value_type;
0440         typedef void difference_type;
0441         typedef void pointer;
0442         typedef void reference;
0443 
0444         explicit output_iterator(OutputIterator& sink_)
0445           : sink(&sink_)
0446         {}
0447         output_iterator(output_iterator const& rhs)
0448           : base_iterator(rhs), sink(rhs.sink)
0449         {}
0450 
0451         output_iterator& operator*() { return *this; }
0452         output_iterator& operator++() 
0453         { 
0454             if (!this->base_iterator::has_buffer())
0455                 ++(*sink);           // increment only if not buffering
0456             return *this; 
0457         } 
0458         output_iterator operator++(int) 
0459         {
0460             if (!this->base_iterator::has_buffer()) {
0461                 output_iterator t(*this);
0462                 ++(*sink); 
0463                 return t; 
0464             }
0465             return *this;
0466         }
0467 
0468 #if defined(BOOST_MSVC)
0469 // 'argument' : conversion from '...' to '...', possible loss of data
0470 #pragma warning (push)
0471 #pragma warning (disable: 4244)
0472 #endif
0473         template <typename T>
0474         void operator=(T const& value) 
0475         { 
0476             if (this->base_iterator::output(value))
0477                 *(*sink) = value; 
0478         }
0479 #if defined(BOOST_MSVC)
0480 #pragma warning (pop)
0481 #endif
0482 
0483         // plain output iterators are considered to be good all the time
0484         bool good() const { return true; }
0485 
0486         // allow to access underlying output iterator
0487         OutputIterator& base() { return *sink; }
0488 
0489     protected:
0490         // this is the wrapped user supplied output iterator
0491         OutputIterator* sink;
0492     };
0493 
0494     ///////////////////////////////////////////////////////////////////////////
0495     template <typename T, typename Elem, typename Traits, typename Properties>
0496     class output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties>
0497       : public output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties
0498           , output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties> >
0499     {
0500     private:
0501         typedef output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties
0502           , output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties> 
0503         > base_type;
0504         typedef karma::ostream_iterator<T, Elem, Traits> base_iterator_type;
0505         typedef std::basic_ostream<Elem, Traits> ostream_type;
0506 
0507     public:
0508         output_iterator(base_iterator_type& sink)
0509           : base_type(sink) {}
0510 
0511         ostream_type& get_ostream() { return (*this->sink).get_ostream(); }
0512         ostream_type const& get_ostream() const { return (*this->sink).get_ostream(); }
0513 
0514         // expose good bit of underlying stream object
0515         bool good() const { return (*this->sink).get_ostream().good(); }
0516     };
0517 
0518     ///////////////////////////////////////////////////////////////////////////
0519     //  Helper class for exception safe enabling of character counting in the
0520     //  output iterator
0521     ///////////////////////////////////////////////////////////////////////////
0522     template <typename OutputIterator>
0523     struct enable_counting
0524     {
0525         enable_counting(OutputIterator& sink_, std::size_t count = 0)
0526           : count_data(sink_, count) {}
0527 
0528         // get number of characters counted since last enable
0529         std::size_t count() const
0530         {
0531             return count_data.get_count();
0532         }
0533 
0534     private:
0535         counting_sink<OutputIterator> count_data;              // for counting
0536     };
0537 
0538     template <typename OutputIterator>
0539     struct disable_counting
0540     {
0541         disable_counting(OutputIterator& sink_)
0542           : count_data(sink_, 0, false) {}
0543 
0544     private:
0545         counting_sink<OutputIterator> count_data;
0546     };
0547 
0548     ///////////////////////////////////////////////////////////////////////////
0549     //  Helper class for exception safe enabling of character buffering in the
0550     //  output iterator
0551     ///////////////////////////////////////////////////////////////////////////
0552     template <typename OutputIterator>
0553     struct enable_buffering
0554     {
0555         enable_buffering(OutputIterator& sink_
0556               , std::size_t width = std::size_t(-1))
0557           : sink(sink_), prev_buffer(NULL), enabled(false)
0558         {
0559             buffer_data.enable(width);
0560             prev_buffer = sink.chain_buffering(&buffer_data);
0561             enabled = true;
0562         }
0563         ~enable_buffering()
0564         {
0565             disable();
0566         }
0567 
0568         // reset buffer chain to initial state
0569         void disable()
0570         {
0571             if (enabled) {
0572                 BOOST_VERIFY(&buffer_data == sink.chain_buffering(prev_buffer));
0573                 enabled = false;
0574             }
0575         }
0576 
0577         // copy to the underlying sink whatever is in the local buffer
0578         bool buffer_copy(std::size_t maxwidth = std::size_t(-1)
0579           , bool disable_ = true)
0580         {
0581             if (disable_)
0582                 disable();
0583             return buffer_data.copy(sink, maxwidth) && sink.good();
0584         }
0585 
0586         // return number of characters stored in the buffer
0587         std::size_t buffer_size() const
0588         {
0589             return buffer_data.buffer_size();
0590         }
0591 
0592         // copy to the remaining characters to the specified sink
0593         template <typename RestIterator>
0594         bool buffer_copy_rest(RestIterator& sink, std::size_t start_at = 0) const
0595         {
0596             return buffer_data.copy_rest(sink, start_at);
0597         }
0598 
0599         // copy the contents to the given output iterator
0600         template <typename OutputIterator_>
0601         bool buffer_copy_to(OutputIterator_& sink
0602           , std::size_t maxwidth = std::size_t(-1)) const
0603         {
0604             return buffer_data.copy(sink, maxwidth);
0605         }
0606 
0607     private:
0608         OutputIterator& sink;
0609         buffer_sink buffer_data;    // for buffering
0610         buffer_sink* prev_buffer;   // previous buffer in chain
0611         bool enabled;
0612     };
0613 
0614     ///////////////////////////////////////////////////////////////////////////
0615     //  Helper class for exception safe disabling of output
0616     ///////////////////////////////////////////////////////////////////////////
0617     template <typename OutputIterator>
0618     struct disable_output
0619     {
0620         disable_output(OutputIterator& sink_)
0621           : sink(sink_), prev_do_output(sink.do_output)
0622         {
0623             sink.do_output = false;
0624         }
0625         ~disable_output()
0626         {
0627             sink.do_output = prev_do_output;
0628         }
0629 
0630         OutputIterator& sink;
0631         bool prev_do_output;
0632     };
0633 
0634     ///////////////////////////////////////////////////////////////////////////
0635     template <typename Sink>
0636     bool sink_is_good(Sink const&)
0637     {
0638         return true;      // the general case is always good
0639     }
0640 
0641     template <typename OutputIterator, typename Derived>
0642     bool sink_is_good(output_iterator<OutputIterator, Derived> const& sink)
0643     {
0644         return sink.good(); // our own output iterators are handled separately
0645     }
0646 
0647 }}}}
0648 
0649 #endif 
0650