123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650 |
- // Copyright (c) 2001-2011 Hartmut Kaiser
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- #if !defined(BOOST_SPIRIT_KARMA_OUTPUT_ITERATOR_MAY_26_2007_0506PM)
- #define BOOST_SPIRIT_KARMA_OUTPUT_ITERATOR_MAY_26_2007_0506PM
- #if defined(_MSC_VER)
- #pragma once
- #endif
- #include <iterator>
- #include <vector>
- #include <algorithm>
- #include <boost/config.hpp>
- #include <boost/noncopyable.hpp>
- #include <boost/mpl/if.hpp>
- #include <boost/spirit/home/karma/generator.hpp>
- #include <boost/spirit/home/support/iterators/ostream_iterator.hpp>
- #include <boost/spirit/home/support/unused.hpp>
- #if defined(BOOST_MSVC) && defined(BOOST_SPIRIT_UNICODE)
- #include <boost/spirit/home/support/char_encoding/unicode.hpp>
- #endif
- namespace boost { namespace spirit { namespace karma { namespace detail
- {
- ///////////////////////////////////////////////////////////////////////////
- // This class is used to keep track of the current position in the output.
- ///////////////////////////////////////////////////////////////////////////
- class position_sink
- {
- public:
- position_sink() : count(0), line(1), column(1) {}
- void tidy() { count = 0; line = 1; column = 1; }
- template <typename T>
- void output(T const& value)
- {
- ++count;
- if (value == '\n') {
- ++line;
- column = 1;
- }
- else {
- ++column;
- }
- }
- std::size_t get_count() const { return count; }
- std::size_t get_line() const { return line; }
- std::size_t get_column() const { return column; }
- private:
- std::size_t count;
- std::size_t line;
- std::size_t column;
- };
- ///////////////////////////////////////////////////////////////////////////
- struct position_policy
- {
- position_policy() {}
- position_policy(position_policy const& rhs)
- : track_position_data(rhs.track_position_data) {}
- template <typename T>
- void output(T const& value)
- {
- // track position in the output
- track_position_data.output(value);
- }
- // return the current count in the output
- std::size_t get_out_count() const
- {
- return track_position_data.get_count();
- }
- // return the current line in the output
- std::size_t get_line() const
- {
- return track_position_data.get_line();
- }
- // return the current column in the output
- std::size_t get_column() const
- {
- return track_position_data.get_column();
- }
- private:
- position_sink track_position_data; // for position tracking
- };
- struct no_position_policy
- {
- no_position_policy() {}
- no_position_policy(no_position_policy const&) {}
- template <typename T>
- void output(T const& /*value*/) {}
- };
- ///////////////////////////////////////////////////////////////////////////
- // This class is used to count the number of characters streamed into the
- // output.
- ///////////////////////////////////////////////////////////////////////////
- template <typename OutputIterator>
- class counting_sink : boost::noncopyable
- {
- public:
- counting_sink(OutputIterator& sink_, std::size_t count_ = 0
- , bool enabled = true)
- : count(count_), initial_count(count), prev_count(0), sink(sink_)
- {
- prev_count = sink.chain_counting(enabled ? this : NULL);
- }
- ~counting_sink()
- {
- if (prev_count) // propagate count
- prev_count->update_count(count-initial_count);
- sink.chain_counting(prev_count);
- }
- void output()
- {
- ++count;
- }
- std::size_t get_count() const { return count; }
- // propagate count from embedded counters
- void update_count(std::size_t c)
- {
- count += c;
- }
- private:
- std::size_t count;
- std::size_t initial_count;
- counting_sink* prev_count; // previous counter in chain
- OutputIterator& sink;
- };
- ///////////////////////////////////////////////////////////////////////////
- template <typename OutputIterator>
- struct counting_policy
- {
- public:
- counting_policy() : count(NULL) {}
- counting_policy(counting_policy const& rhs) : count(rhs.count) {}
- // functions related to counting
- counting_sink<OutputIterator>* chain_counting(
- counting_sink<OutputIterator>* count_data)
- {
- counting_sink<OutputIterator>* prev_count = count;
- count = count_data;
- return prev_count;
- }
- template <typename T>
- void output(T const&)
- {
- // count characters, if appropriate
- if (NULL != count)
- count->output();
- }
- private:
- counting_sink<OutputIterator>* count; // for counting
- };
- struct no_counting_policy
- {
- no_counting_policy() {}
- no_counting_policy(no_counting_policy const&) {}
- template <typename T>
- void output(T const& /*value*/) {}
- };
- ///////////////////////////////////////////////////////////////////////////
- // The following classes are used to intercept the output into a buffer
- // allowing to do things like alignment, character escaping etc.
- ///////////////////////////////////////////////////////////////////////////
- class buffer_sink : boost::noncopyable
- {
- // wchar_t is only 16-bits on Windows. If BOOST_SPIRIT_UNICODE is
- // defined, the character type is 32-bits wide so we need to make
- // sure the buffer is at least that wide.
- #if (defined(_MSC_VER) || defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) && defined(BOOST_SPIRIT_UNICODE)
- typedef spirit::char_encoding::unicode::char_type buffer_char_type;
- #else
- typedef wchar_t buffer_char_type;
- #endif
- public:
- buffer_sink()
- : width(0) {}
- ~buffer_sink()
- {
- tidy();
- }
- void enable(std::size_t width_)
- {
- tidy(); // release existing buffer
- width = (width_ == std::size_t(-1)) ? 0 : width_;
- buffer.reserve(width);
- }
- void tidy()
- {
- buffer.clear();
- width = 0;
- }
- template <typename T>
- void output(T const& value)
- {
- BOOST_STATIC_ASSERT(sizeof(T) <= sizeof(buffer_char_type));
- buffer.push_back(value);
- }
- template <typename OutputIterator_>
- bool copy(OutputIterator_& sink, std::size_t maxwidth) const
- {
- #if defined(BOOST_MSVC)
- #pragma warning(push)
- #pragma warning(disable: 4267)
- #endif
- typename std::basic_string<buffer_char_type>::const_iterator end =
- buffer.begin() + (std::min)(buffer.size(), maxwidth);
- #if defined(BOOST_MSVC)
- #pragma warning(disable: 4244) // conversion from 'x' to 'y', possible loss of data
- #endif
- std::copy(buffer.begin(), end, sink);
- #if defined(BOOST_MSVC)
- #pragma warning(pop)
- #endif
- return true;
- }
- template <typename RestIterator>
- bool copy_rest(RestIterator& sink, std::size_t start_at) const
- {
- #if defined(BOOST_MSVC)
- #pragma warning(push)
- #pragma warning(disable: 4267)
- #endif
- typename std::basic_string<buffer_char_type>::const_iterator begin =
- buffer.begin() + (std::min)(buffer.size(), start_at);
- #if defined(BOOST_MSVC)
- #pragma warning(disable: 4244) // conversion from 'x' to 'y', possible loss of data
- #endif
- std::copy(begin, buffer.end(), sink);
- #if defined(BOOST_MSVC)
- #pragma warning(pop)
- #endif
- return true;
- }
- std::size_t buffer_size() const
- {
- return buffer.size();
- }
- private:
- std::size_t width;
- std::basic_string<buffer_char_type> buffer;
- };
- ///////////////////////////////////////////////////////////////////////////
- struct buffering_policy
- {
- public:
- buffering_policy() : buffer(NULL) {}
- buffering_policy(buffering_policy const& rhs) : buffer(rhs.buffer) {}
- // functions related to buffering
- buffer_sink* chain_buffering(buffer_sink* buffer_data)
- {
- buffer_sink* prev_buffer = buffer;
- buffer = buffer_data;
- return prev_buffer;
- }
- template <typename T>
- bool output(T const& value)
- {
- // buffer characters, if appropriate
- if (NULL != buffer) {
- buffer->output(value);
- return false;
- }
- return true;
- }
- bool has_buffer() const { return NULL != buffer; }
- private:
- buffer_sink* buffer;
- };
- struct no_buffering_policy
- {
- no_buffering_policy() {}
- no_buffering_policy(no_buffering_policy const&) {}
- template <typename T>
- bool output(T const& /*value*/)
- {
- return true;
- }
- bool has_buffer() const { return false; }
- };
- ///////////////////////////////////////////////////////////////////////////
- // forward declaration only
- template <typename OutputIterator>
- struct enable_buffering;
- template <typename OutputIterator, typename Properties
- , typename Derived = unused_type>
- class output_iterator;
- ///////////////////////////////////////////////////////////////////////////
- template <typename Buffering, typename Counting, typename Tracking>
- struct output_iterator_base : Buffering, Counting, Tracking
- {
- typedef Buffering buffering_policy;
- typedef Counting counting_policy;
- typedef Tracking tracking_policy;
- output_iterator_base() {}
- output_iterator_base(output_iterator_base const& rhs)
- : buffering_policy(rhs), counting_policy(rhs), tracking_policy(rhs)
- {}
- template <typename T>
- bool output(T const& value)
- {
- this->counting_policy::output(value);
- this->tracking_policy::output(value);
- return this->buffering_policy::output(value);
- }
- };
- template <typename Buffering, typename Counting, typename Tracking>
- struct disabling_output_iterator : Buffering, Counting, Tracking
- {
- typedef Buffering buffering_policy;
- typedef Counting counting_policy;
- typedef Tracking tracking_policy;
- disabling_output_iterator() : do_output(true) {}
- disabling_output_iterator(disabling_output_iterator const& rhs)
- : buffering_policy(rhs), counting_policy(rhs), tracking_policy(rhs)
- , do_output(rhs.do_output)
- {}
- template <typename T>
- bool output(T const& value)
- {
- if (!do_output)
- return false;
- this->counting_policy::output(value);
- this->tracking_policy::output(value);
- return this->buffering_policy::output(value);
- }
- bool do_output;
- };
- ///////////////////////////////////////////////////////////////////////////
- template <typename OutputIterator, typename Properties, typename Derived>
- struct make_output_iterator
- {
- // get the most derived type of this class
- typedef typename mpl::if_<
- traits::not_is_unused<Derived>, Derived
- , output_iterator<OutputIterator, Properties, Derived>
- >::type most_derived_type;
- static const generator_properties::enum_type properties = static_cast<generator_properties::enum_type>(Properties::value);
- typedef typename mpl::if_c<
- (properties & generator_properties::tracking) ? true : false
- , position_policy, no_position_policy
- >::type tracking_type;
- typedef typename mpl::if_c<
- (properties & generator_properties::buffering) ? true : false
- , buffering_policy, no_buffering_policy
- >::type buffering_type;
- typedef typename mpl::if_c<
- (properties & generator_properties::counting) ? true : false
- , counting_policy<most_derived_type>, no_counting_policy
- >::type counting_type;
- typedef typename mpl::if_c<
- (properties & generator_properties::disabling) ? true : false
- , disabling_output_iterator<buffering_type, counting_type, tracking_type>
- , output_iterator_base<buffering_type, counting_type, tracking_type>
- >::type type;
- };
- ///////////////////////////////////////////////////////////////////////////
- // Karma uses an output iterator wrapper for all output operations. This
- // is necessary to avoid the dreaded 'scanner business' problem, i.e. the
- // dependency of rules and grammars on the used output iterator.
- //
- // By default the user supplied output iterator is wrapped inside an
- // instance of this internal output_iterator class.
- //
- // This output_iterator class normally just forwards to the embedded user
- // supplied iterator. But it is possible to enable additional functionality
- // on demand, such as counting, buffering, and position tracking.
- ///////////////////////////////////////////////////////////////////////////
- template <typename OutputIterator, typename Properties, typename Derived>
- class output_iterator
- : public make_output_iterator<OutputIterator, Properties, Derived>::type
- {
- private:
- // base iterator type
- typedef typename make_output_iterator<
- OutputIterator, Properties, Derived>::type base_iterator;
- public:
- typedef std::output_iterator_tag iterator_category;
- typedef void value_type;
- typedef void difference_type;
- typedef void pointer;
- typedef void reference;
- explicit output_iterator(OutputIterator& sink_)
- : sink(&sink_)
- {}
- output_iterator(output_iterator const& rhs)
- : base_iterator(rhs), sink(rhs.sink)
- {}
- output_iterator& operator*() { return *this; }
- output_iterator& operator++()
- {
- if (!this->base_iterator::has_buffer())
- ++(*sink); // increment only if not buffering
- return *this;
- }
- output_iterator operator++(int)
- {
- if (!this->base_iterator::has_buffer()) {
- output_iterator t(*this);
- ++(*sink);
- return t;
- }
- return *this;
- }
- #if defined(BOOST_MSVC)
- // 'argument' : conversion from '...' to '...', possible loss of data
- #pragma warning (push)
- #pragma warning (disable: 4244)
- #endif
- template <typename T>
- void operator=(T const& value)
- {
- if (this->base_iterator::output(value))
- *(*sink) = value;
- }
- #if defined(BOOST_MSVC)
- #pragma warning (pop)
- #endif
- // plain output iterators are considered to be good all the time
- bool good() const { return true; }
- // allow to access underlying output iterator
- OutputIterator& base() { return *sink; }
- protected:
- // this is the wrapped user supplied output iterator
- OutputIterator* sink;
- };
- ///////////////////////////////////////////////////////////////////////////
- template <typename T, typename Elem, typename Traits, typename Properties>
- class output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties>
- : public output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties
- , output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties> >
- {
- private:
- typedef output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties
- , output_iterator<karma::ostream_iterator<T, Elem, Traits>, Properties>
- > base_type;
- typedef karma::ostream_iterator<T, Elem, Traits> base_iterator_type;
- typedef std::basic_ostream<Elem, Traits> ostream_type;
- public:
- output_iterator(base_iterator_type& sink)
- : base_type(sink) {}
- ostream_type& get_ostream() { return (*this->sink).get_ostream(); }
- ostream_type const& get_ostream() const { return (*this->sink).get_ostream(); }
- // expose good bit of underlying stream object
- bool good() const { return (*this->sink).get_ostream().good(); }
- };
- ///////////////////////////////////////////////////////////////////////////
- // Helper class for exception safe enabling of character counting in the
- // output iterator
- ///////////////////////////////////////////////////////////////////////////
- template <typename OutputIterator>
- struct enable_counting
- {
- enable_counting(OutputIterator& sink_, std::size_t count = 0)
- : count_data(sink_, count) {}
- // get number of characters counted since last enable
- std::size_t count() const
- {
- return count_data.get_count();
- }
- private:
- counting_sink<OutputIterator> count_data; // for counting
- };
- template <typename OutputIterator>
- struct disable_counting
- {
- disable_counting(OutputIterator& sink_)
- : count_data(sink_, 0, false) {}
- private:
- counting_sink<OutputIterator> count_data;
- };
- ///////////////////////////////////////////////////////////////////////////
- // Helper class for exception safe enabling of character buffering in the
- // output iterator
- ///////////////////////////////////////////////////////////////////////////
- template <typename OutputIterator>
- struct enable_buffering
- {
- enable_buffering(OutputIterator& sink_
- , std::size_t width = std::size_t(-1))
- : sink(sink_), prev_buffer(NULL), enabled(false)
- {
- buffer_data.enable(width);
- prev_buffer = sink.chain_buffering(&buffer_data);
- enabled = true;
- }
- ~enable_buffering()
- {
- disable();
- }
- // reset buffer chain to initial state
- void disable()
- {
- if (enabled) {
- BOOST_VERIFY(&buffer_data == sink.chain_buffering(prev_buffer));
- enabled = false;
- }
- }
- // copy to the underlying sink whatever is in the local buffer
- bool buffer_copy(std::size_t maxwidth = std::size_t(-1)
- , bool disable_ = true)
- {
- if (disable_)
- disable();
- return buffer_data.copy(sink, maxwidth) && sink.good();
- }
- // return number of characters stored in the buffer
- std::size_t buffer_size() const
- {
- return buffer_data.buffer_size();
- }
- // copy to the remaining characters to the specified sink
- template <typename RestIterator>
- bool buffer_copy_rest(RestIterator& sink, std::size_t start_at = 0) const
- {
- return buffer_data.copy_rest(sink, start_at);
- }
- // copy the contents to the given output iterator
- template <typename OutputIterator_>
- bool buffer_copy_to(OutputIterator_& sink
- , std::size_t maxwidth = std::size_t(-1)) const
- {
- return buffer_data.copy(sink, maxwidth);
- }
- private:
- OutputIterator& sink;
- buffer_sink buffer_data; // for buffering
- buffer_sink* prev_buffer; // previous buffer in chain
- bool enabled;
- };
- ///////////////////////////////////////////////////////////////////////////
- // Helper class for exception safe disabling of output
- ///////////////////////////////////////////////////////////////////////////
- template <typename OutputIterator>
- struct disable_output
- {
- disable_output(OutputIterator& sink_)
- : sink(sink_), prev_do_output(sink.do_output)
- {
- sink.do_output = false;
- }
- ~disable_output()
- {
- sink.do_output = prev_do_output;
- }
- OutputIterator& sink;
- bool prev_do_output;
- };
- ///////////////////////////////////////////////////////////////////////////
- template <typename Sink>
- bool sink_is_good(Sink const&)
- {
- return true; // the general case is always good
- }
- template <typename OutputIterator, typename Derived>
- bool sink_is_good(output_iterator<OutputIterator, Derived> const& sink)
- {
- return sink.good(); // our own output iterators are handled separately
- }
- }}}}
- #endif
|