I/O Formatting Manipulators

1.   Introduction
1.1.   The Problem
1.2.   The Solution
2.   Getting Started
2.1.   Outermost Construct
2.2.   std::map; std::pair and std::complex
2.3.   nD array and container types
3.   Formatter Objects
3.1.   Overview
3.2.   boost::io::details::format_traits
3.3.   boost::io::formatter_t
3.3.1.   Formatting Options
3.3.2.   Spacing Options
3.3.3.   Configuration From Another Formatter Object
3.3.4.   Constructors
3.4.   boost::io::formatter
4.   The Manipulators
4.1.   Format List
4.1.1.   boost::io::formatlist_t
4.1.2.   boost::io::formatlist
4.1.3.   boost::io::formatlistex
4.1.4.   boost::io::formatlistfn
4.2.   Format Object
4.2.1.   boost::io::formatob_t
4.2.2.   boost::io::formatob
5.   Outputters
5.1.   Outputter Function Objects
5.2.   boost::io::basic_output
5.3.   boost::io::pair_output
5.3.1.   Generators
5.4.   boost::io::detail::list_output
5.5.   boost::io::container_output
5.5.1.   Generators
5.6.   boost::io::array_output
5.6.1.   Generators
6.   Portability
7.   Future Directions
7.1.   Position/Context Information
7.2.   pre/post-separator output
8.   Acknowledgements

1

Introduction
1.1. The Problem
 
The C++ Input/Output library provides a mechanism for customizing the way a class is represented on a linear text stream. There are output operations for the basic data types as well as for std::complex and other data types in the standard library.
 
Having said that, there are no output operations for any of the STL container types. There is a reason for this: how do we represent the list? Different applications would want different ways for the list to be represented, so there is no easy way to specify a default format. What if you need to output a sub-list? Or have the same format across different container types? Or have different formatting for different objects that have the same container type?
1.2. The Solution
 
Designing a library that can cope with these problems, as well as others not considered here, while remaining efficient is no easy task. There are other attempts to solve these sorts of problems.
 
The motivation behind using manipulators is that they are already designed into the C++ I/O library and require little overhead in the output process. They also give the user maximum choice in how the data being outputted is formatted.
2

Getting Started
 
In order to output a container or C-style array, you need to work out what form the manipulator will take. This section will outline how to construct this for most types. [Note: Work from the outermost part in when you have a complex type.]
2.1. Outermost Construct
 
For a container that has a begin() and end() function returning a forward iterator (including the STL-based containers and std::string), you can use the formatlist manipulator simply passing that container.
 
For C-style arrays and strings, you need to supply the start and end points as parameters to fortmatlist. This form can also be used for sub-lists.
 
For other constructs (such as std::pair), use fortmatob with the appropriate outputter. See the std::pair and std::complex output example to see a usage of this.
 
2.2. std::map; std::pair and std::complex
 
For std::pair, you need to bind a pair_output outputter to the formatlist manipulator; for std::complex, you only need to do this if you want to override the default formatting behaviour. This is needed for std::map objects because they iterate over std::pair types.
 
2.3. nD array and container types
 
For array constructs, you need to use an array_output outputter and specify the length of the array.
 
For container constructs, you need to use an array_output outputter; this will output the entire length of that container.
 
[Note: You can mix array and container constructs. ]
 
examples: 2D output; 3D output
3

Formatter Objects
3.1. Overview
 
The formatter object forms the basis for all formatting configuration within this library.
 
[Example:
boost::io::formatter< char > fmt;
fmt.format( '(' , ')' );
]
 
[Example:
boost::io::formatter< char * > fmt2;
fmt2.format( "--" ).space( true, true );
]
3.2. boost::io::details::format_traits
 
 
[Note: This class is part of the implementation details, and should only be extended to support format types not provided for here, such as std::basic_string types. It is also not intended for general use. ]
 
The format_traits class provides the default values for the format constants in a formatter object. It has the following form:
 
template<> class boost::io::details::format_traits< FormatType >
{
public:
static FormatType open_default;
static FormatType close_default;
static FormatType separator_default;
public:
static inline bool isok( FormatType ) throw();
};
 
attribute/method default description
open_default [ The default value for the open list parameter.
close_default ] The default value for the close list parameter.
separator_default , The default value for the separator parameter.
isok( FormatType ft ) ft != 0 Checks to see if the FormatType value is ok to be rendered.
3.3. boost::io::formatter_t
 
 
[todo]
3.3.1. Formatting Options
 
[todo]
3.3.2. Spacing Options
 
[todo]
3.3.3. Configuration From Another Formatter Object
 
[todo]
3.3.4. Constructors
 
[todo]
3.4. boost::io::formatter
 
 
[todo]
4

The Manipulators
4.1. Format List
 
 
The list formatting manipulators provide the mechanism for rendering lists to an output stream.
4.1.1. boost::io::formatlist_t
 
[todo]
4.1.2. boost::io::formatlist
 
These are the basic forms of the formatlist manipulator.
 
template< typename ForwardIterator >
inline boost::io::formatlist_t< ForwardIterator > boost::io::formatlist
(
ForwardIterator first,
ForwardIterator last
);
 
This specifies a list from first to last that is to be rendered to the output stream.
 
[Example:
int i[ 4 ] = { 3, 6, 9, 12 };
std::cout << boost::io::formatlist( i, i + 4 );
]
 
template< class Container >
inline boost::io::formatlist_t< typename Container::iterator > boost::io::formatlist
(
Container & c
);
 
This specifies a container to be rendered to the output stream, and is equivalent to
boost::io::formatlist( c.begin(), c.end())
but is shorter to write.
 
[Example:
std::vector< int > v( 10 );
std::generate( v.begin(), v.end(), std::rand );
std::cout << boost::io::formatlist( v );
]
 
The following forms of the list format manipulator accept a formatter object to specify how the list is rendered.
 
[Note: These manipulator forms will inherit the format type from the formatter object, and thus it does not need to be explicitly specified. ]
 
template< typename ForwardIterator, typename FormatType, class RefType >
inline boost::io::formatlist_t< ForwardIterator, FormatType > boost::io::formatlist
(
ForwardIterator first,
ForwardIterator last,
const boost::io::formatter_t< FormatType, RefType > & fmt
);
 
This specifies a list from first to last that is to be rendered to the output stream using the formatting specified in fmt as its default values.
 
[Example:
std::cout << boost::io::formatlist( i, i + 4, fmt );
std::cout << boost::io::formatlist( i, i + 4, fmt2 );
[Note: This example makes use of variables defined in earlier examples. ]]
 
template< class Container, typename FormatType, class RefType >
inline boost::io::formatlist_t< typename Container::iterator, FormatType > boost::io::formatlist
(
Container & c,
const boost::io::formatter_t< FormatType, RefType > & fmt
);
 
This specifies a container that is to be rendered to the output stream using the formatting specified in fmt as its default values.
 
[Example:
std::cout << boost::io::formatlist( v, fmt );
std::cout << boost::io::formatlist( v, fmt2 );
[Note: This example makes use of variables defined in earlier examples. ]]
4.1.3. boost::io::formatlistex
 
These variants on the basic list format manipulator are to allow wide character and string types to be used.
 
template< typename FormatType, typename ForwardIterator >
inline boost::io::formatlist_t< ForwardIterator, FormatList > boost::io::formatlistex
(
ForwardIterator first,
ForwardIterator last
);
 
This specifies FormatType and should be used if you need string or wide-character types. This is the list range version.
 
[Example:
char * str = "Hello World!" ;
std::cout << boost::io::formatlistex< char * >( str, str + std::strlen( str )).format( "==>" , "<==" );
]
 
template< typename FormatType, class Container >
inline boost::io::formatlist_t< typename Container::iterator, FormatList > boost::io::formatlistex
(
Container & c
);
 
This specifies FormatType and should be used if you need string or wide-character types. This is the container version.
 
[Example:
std::list< char > l;
l.push_back( 'A' );
l.push_back( 'B' );
l.push_back( 'C' );
std::cout << boost::io::formatlistex< char * >( l ).format( "==" ).space( true, true );
]
4.1.4. boost::io::formatlistfn
 
These variants on the basic list format manipulator allow the user to specify the way each item in the list is rendered. For a more detailed description of what outputters are, see the relevant section.
 
For examples of these manipulators, see the outputter section.
 
[Note: These manipulator forms will inherit the format type from the outputter object, and thus it does not need to be explicitly specified. ]
 
template< typename ForwardIterator, typename Outputter >
inline boost::io::formatlist_t< ForwardIterator, typename Outputter::listfmt_type, Outputter > boost::io::formatlistfn
(
ForwardIterator first,
ForwardIterator last,
Outputter out
);
 
This is the sub-list variant.
 
template< class Container, typename Outputter >
inline boost::io::formatlist_t< typename Container::iterator, typename Outputter::listfmt_type, Outputter > boost::io::formatlistfn
(
Container c,
Outputter out
);
 
This is the STL container variant.
 
These variants allow both outputter and default formatting to be specified, completing the set.
 
[Note: These manipulator forms will inherit the format type from the outputter object, and thus it does not need to be explicitly specified. This must be the same as the format type used in the formatter object used to inherit the string values. ]
 
template< typename ForwardIterator, class Outputter, class RefType >
inline boost::io::formatlist_t< ForwardIterator, typename Outputter::listfmt_type, Outputter > boost::io::formatlistfn
(
ForwardIterator first,
ForwardIterator last,
Outputter o,
const boost::io::formatter_t< typename Outputter::listfmt_type, RefType > & fmt
);
 
This is the sub-list variant.
 
template< class Container, class Outputter, class RefType >
inline boost::io::formatlist_t< typename Container::iterator, typename Outputter::listfmt_type, Outputter > boost::io::formatlistfn
(
Container & c,
Outputter o,
const  boost::io::formatter_t< typename Outputter::listfmt_type, RefType > & fmt
);
 
This is the STL container variant.
4.2. Format Object
 
 
[to do]
4.2.1. boost::io::formatob_t
 
[todo]
4.2.2. boost::io::formatob
 
[todo]
5

Outputters
 
5.1. Outputter Function Objects
 
[todo]
5.2. boost::io::basic_output
 
 
[todo]
5.3. boost::io::pair_output
 
 
[todo]
5.3.1. Generators
 
[todo]
5.4. boost::io::detail::list_output
 
 
[todo]
 
[Note: This class is part of the implementation details. It encapsulates the list rendering functionality used by boost::io::formatlist_t, boost::io::array_output and boost::io::container_output. You should use one of those classes if you want list rendering functionality. ]
5.5. boost::io::container_output
 
 
[todo]
5.5.1. Generators
 
[todo]
5.6. boost::io::array_output
 
 
[todo]
5.6.1. Generators
 
[todo]
6

Portability
 
The code has been succesfully tested on:
  1. MSVC 7.0;
  2. Borland C++Compiler 5.5.1;
  3. GNU G++ 3.0.3 (under the i686-pc-cygwin environment)
in the Win32 environment on a Windows XP/Pentium II machine.
 
The code does not work on the following:
  1. GNU G++ 2.95.3-5 (under the i686-pc-cygwin environment).
 
[Note: I do not have the facilities to test it on other machines/compilers. ]
7

Future Directions
7.1. Position/Context Information
 
Adding support for position information within a list. This would allow more advanced formatting, like numbering each item or providing special formatting for brace elements (i.e. the middle extension glyph).
 
I am currently thinking of supporting this as an extra (optional) parameter to the function operator of the output functor. This parameter will be a context-information object from the parent outputter that gives information such as the length of the sub-list being outputted and the current position within that sub-list. Other information may be added at a future date.
7.2. pre/post-separator output
 
Add support for outputting a string before and after a separator. This would simplify the rendering of more more advanced constructs such as XML tags.
8

Acknowledgements
 
This library was designed and implemented by Reece H. Dunn.
 
The output functors were based on a comment in the "IO for STL containers" thread on the boost developers mailing list.
 
Special thanks to:
[1]
Martin Henson: For giving me a reason to create the library in the first place!
[2]
Paul A. Bristow: For his comments and suggestions, especially getting me to think about supporting nD constructs.
[3]
Terje Slettebø: For his feedback on standard/boost issues in my code.
[4]
Gennadiy Rozental: For issues relating to the documentation.

Copyright © 2003 Reece H. Dunn