123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- // Boost.TypeErasure library
- //
- // Copyright 2011 Steven Watanabe
- //
- // 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)
- //
- // $Id$
- //[print_sequence
- /*`
- (For the source of this example see
- [@boost:/libs/type_erasure/example/print_sequence.cpp print_sequence.cpp])
- This example defines a class hierarchy that allows a sequence
- to be formatted in several different ways. We'd like to be
- able to handle any sequence and any stream type, since the
- range formatting is independent of the formatting of
- individual elements. Thus, our interface needs to look
- something like this:
- ``
- class abstract_printer {
- public:
- template<class CharT, class Traits, class Range>
- virtual void print(std::basic_ostream<CharT, Traits>& os, const Range& r) const = 0;
- };
- ``
- Unfortunately, this is illegal because a virtual function
- cannot be a template. However, we can define a
- class with much the same behavior using Boost.TypeErasure.
- */
- #include <boost/type_erasure/any.hpp>
- #include <boost/type_erasure/iterator.hpp>
- #include <boost/type_erasure/operators.hpp>
- #include <boost/type_erasure/tuple.hpp>
- #include <boost/type_erasure/same_type.hpp>
- #include <boost/range/begin.hpp>
- #include <boost/range/end.hpp>
- #include <boost/range/iterator.hpp>
- #include <iostream>
- #include <iomanip>
- #include <vector>
- using namespace boost::type_erasure;
- struct _t : placeholder {};
- struct _iter : placeholder {};
- struct _os : placeholder {};
- template<class T, class U = _self>
- struct base_and_derived
- {
- static T& apply(U& arg) { return arg; }
- };
- namespace boost {
- namespace type_erasure {
- template<class T, class U, class Base>
- struct concept_interface<base_and_derived<T, U>, Base, U> : Base
- {
- operator typename rebind_any<Base, const T&>::type() const
- {
- return call(base_and_derived<T, U>(), const_cast<concept_interface&>(*this));
- }
- operator typename rebind_any<Base, T&>::type()
- {
- return call(base_and_derived<T, U>(), *this);
- }
- };
- }
- }
- // abstract_printer - An abstract base class for formatting sequences.
- class abstract_printer {
- public:
- // print - write a sequence to a std::ostream in a manner
- // specific to the derived class.
- //
- // Requires: Range must be a Forward Range whose elements can be
- // printed to os.
- template<class CharT, class Traits, class Range>
- void print(std::basic_ostream<CharT, Traits>& os, const Range& r) const {
- // Capture the arguments
- typename boost::range_iterator<const Range>::type
- first(boost::begin(r)),
- last(boost::end(r));
- tuple<requirements, _os&, _iter, _iter> args(os, first, last);
- // and forward to the real implementation
- do_print(get<0>(args), get<1>(args), get<2>(args));
- }
- virtual ~abstract_printer() {}
- protected:
- // define the concept requirements of the arguments of
- // print and typedef the any types.
- typedef boost::mpl::vector<
- base_and_derived<std::ios_base, _os>,
- ostreamable<_os, _t>,
- ostreamable<_os, const char*>,
- forward_iterator<_iter, const _t&>,
- same_type<_t, forward_iterator<_iter, const _t&>::value_type>
- > requirements;
- typedef boost::type_erasure::any<requirements, _os&> ostream_type;
- typedef boost::type_erasure::any<requirements, _iter> iterator_type;
- // do_print - This method must be implemented by derived classes
- virtual void do_print(
- ostream_type os, iterator_type first, iterator_type last) const = 0;
- };
- // separator_printer - writes the elements of a sequence
- // separated by a fixed string. For example, if
- // the separator is ", " separator_printer produces
- // a comma separated list.
- class separator_printer : public abstract_printer {
- public:
- explicit separator_printer(const std::string& sep) : separator(sep) {}
- protected:
- virtual void do_print(
- ostream_type os, iterator_type first, iterator_type last) const {
- if(first != last) {
- os << *first;
- ++first;
- for(; first != last; ++first) {
- os << separator.c_str() << *first;
- }
- }
- }
- private:
- std::string separator;
- };
- // column_separator_printer - like separator_printer, but
- // also inserts a line break after every n elements.
- class column_separator_printer : public abstract_printer {
- public:
- column_separator_printer(const std::string& sep, std::size_t num_columns)
- : separator(sep),
- cols(num_columns)
- {}
- protected:
- virtual void do_print(
- ostream_type os, iterator_type first, iterator_type last) const {
- std::size_t count = 0;
- for(; first != last; ++first) {
- os << *first;
- boost::type_erasure::any<requirements, _iter> temp = first;
- ++temp;
- if(temp != last) {
- os << separator.c_str();
- }
- if(++count % cols == 0) {
- os << "\n";
- }
- }
- }
- private:
- std::string separator;
- std::size_t cols;
- };
- // aligned_column_printer - formats a sequence in columns
- // reading down. For example, given the sequence
- // { 1, 2, 3, 4, 5 }, aligned_column_printer might print
- // 1 4
- // 2 5
- // 3
- class aligned_column_printer : public abstract_printer {
- public:
- aligned_column_printer(std::size_t column_width, std::size_t num_columns)
- : width(column_width),
- cols(num_columns)
- {}
- protected:
- virtual void do_print(
- ostream_type os, iterator_type first, iterator_type last) const
- {
- if(first == last) return;
- std::vector<iterator_type> column_iterators;
- // find the tops of the columns
- std::size_t count = 0;
- for(iterator_type iter = first; iter != last; ++iter) {
- ++count;
- }
- std::size_t rows = (count + cols - 1) / cols;
- count = 0;
- for(iterator_type iter = first; iter != last; ++iter) {
- if(count % rows == 0) {
- column_iterators.push_back(iter);
- }
- ++count;
- }
- iterator_type last_col = column_iterators.back();
- // print the full rows
- while(column_iterators.back() != last) {
- for(std::vector<iterator_type>::iterator
- iter = column_iterators.begin(),
- end = column_iterators.end(); iter != end; ++iter)
- {
- static_cast<std::ios_base&>(os).width(width);
- os << **iter;
- ++*iter;
- }
- os << "\n";
- }
- // print the rows that are missing the last column
- column_iterators.pop_back();
- if(!column_iterators.empty()) {
- while(column_iterators.back() != last_col) {
- for(std::vector<iterator_type>::iterator
- iter = column_iterators.begin(),
- end = column_iterators.end(); iter != end; ++iter)
- {
- static_cast<std::ios_base&>(os).width(width);
- os << **iter;
- ++*iter;
- }
- os << "\n";
- }
- }
- }
- private:
- std::size_t width;
- std::size_t cols;
- };
- int main() {
- int test[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
- separator_printer p1(",");
- p1.print(std::cout, test);
- std::cout << std::endl;
- column_separator_printer p2(",", 4);
- p2.print(std::cout, test);
- std::cout << std::endl;
- aligned_column_printer p3(16, 4);
- p3.print(std::cout, test);
- }
- //]
|