Review of Daryle Walker's "More IO" library begins today, August 21, 2004.

The review of Daryle Walker's "More IO" library begins today, August 21, 2004. Download: http://groups.yahoo.com/group/boost/files/more_io_4.zip [or] http://boost-sandbox.sourceforge.net/more_io_4.zip Description: Provides a multitude of I/O-oriented extensions. Some are extra manipulators; variants of "std::endl", a resetting manipulator, and a configurable manipulator. The library includes a set of base class templates for wrapping a new stream-buffer type around a stream class. Changes from the last interim version (called "more_io_3b.zip"): * split the manipulator header into several headers * refined the license statements in some already-affected files Changes from the first formal review (called "more_io.zip"): * refined the interface and implementation of array-streams and stream-buffer wrappers (including a wrapping example) * added the null-stream, value-stream, and pointer-stream headers * added generalizations to the new-line and skip-line manipulators * added the non-oriented 'reset' and 'form' manipulators * split the manipulator header into several headers * changed the license statements Your comments may be brief or lengthy, but basically the Review Manager needs your evaluation of the library. If you identify problems along the way, please note if they are minor, serious, or showstoppers. Here are some questions you might want to answer in your review: What is your evaluation of the design? What is your evaluation of the implementation? What is your evaluation of the documentation? What is your evaluation of the potential usefulness of the library? Did you try to use the library? With what compiler? Did you have any problems? How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? Are you knowledgeable about the problem domain? And finally, every review should answer this question: Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall opinion. For information about submitting a Formal Review, see http://www.boost.org/more/formal_review_process.htm The Review manager is: Tom Brinkman reportbase@yahoo.com

"tom brinkman" <reportbase@yahoo.com> wrote in message news:cg8di6$jat$1@sea.gmane.org...
The review of Daryle Walker's "More IO" library begins today, August 21, 2004.
I'll submit a review later. Right now I'm just trying to compile some examples. I've found that I can't get basic_array_stream to compile unless I explicitly specify the traits template argument, although it's documented to have the obvious default. The following produces an error 'basic_array_stream: too few template arguments' (VC7.1 and como). #include <boost/io/array_stream.hpp> int main() { boost::io::basic_array_stream<1000, char> io; } Jonathan

On 8/21/04 6:19 PM, "Jonathan Turkanis" <technews@kangaroologic.com> wrote:
"tom brinkman" <reportbase@yahoo.com> wrote in message news:cg8di6$jat$1@sea.gmane.org...
The review of Daryle Walker's "More IO" library begins today, August 21, 2004.
I'll submit a review later. Right now I'm just trying to compile some examples. I've found that I can't get basic_array_stream to compile unless I explicitly specify the traits template argument, although it's documented to have the obvious default. The following produces an error 'basic_array_stream: too few template arguments' (VC7.1 and como).
#include <boost/io/array_stream.hpp>
int main() { boost::io::basic_array_stream<1000, char> io; }
Have you figured this out? Are you sure that you're getting the new "io_fwd.hpp" that I supply with the rest of the new files? The new version of the header forward declares the array-streams, and supplies a critical default for the third template argument. (There's a version of "io_fwd.hpp" already in Boost that doesn't have the new stuff. So make sure the new version is found first.) -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

"Daryle Walker" <darylew@hotmail.com> wrote in message:
On 8/21/04 6:19 PM, "Jonathan Turkanis" <technews@kangaroologic.com> wrote:
Have you figured this out? Are you sure that you're getting the new "io_fwd.hpp" that I supply with the rest of the new files? The new version of the header forward declares the array-streams, and supplies a critical default for the third template argument. (There's a version of "io_fwd.hpp" already in Boost that doesn't have the new stuff. So make sure the new version is found first.)
Yup, that was it. I reordered the include paths and now it works. Jonathan

"tom brinkman" wrote:
The review of Daryle Walker's "More IO" library begins today, August 21, 2004.
I took look on the library. It definitely contains useful functionality, but: a) its documentation is bad (details bellow) and must be rewritten (or rather actually written), b) none of tests compiled, due to bugs in code, c) it may be considered to use inline definitions everywhere instead of out-of-class definitions. It would make code shorter, easier to grok and friendlier to older compilers. d) more functionality may be considered, see item [25] bellow e) naming conventions may be reconsidered (see item [5]) I recommend to fix points (a) and (b) first. Then and only then it should be added to Boost, not in current state. (It would not require another full review, IMHO.) More issues and nitpicks are listed bellow. /Pavel _______________________________________________________________ 1. docs: ios_state.html is missing. Dtto ios_state.hpp. _______________________________________________________________ 2. docs: some introduction into the library would help. _______________________________________________________________ 3. docs: source code snippets should be syntax colorized _______________________________________________________________ 4. #if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif should be put into each of headers. It has positive effect on VC ad Intel C++ compilation times. _______________________________________________________________ 5. naming conventions: some names as basic_constpointerbuf are quite hard to read. Maybe they should basic_const_pointer_buf (This is just subjective opinion of me.) _______________________________________________________________ 7. stream_buf_wrapping.hpp: there are three hardcoded constructors like: template < typename T1, typename T2, typename T3 > basic_wrapping_ios( T1 x1, T2 x2, T3 x3 ) for 1, 2 and 3 parameters though base_from_member supports up to 10 parameters. Boost.Preprocessor can be used here to generate contructors of all available arities. Likewise the basic_wrapping_XYZ bellow. _______________________________________________________________ 8. stream_buf_wrapping.hpp and others, a nitpick: The name BOOST_PRIVATE_WRAPPER may be more unique, e.g. BOOST_IO_PRIVATE_WRAPPER to avoid any chance of collision. _______________________________________________________________ 9. stream_buf_wrapping.hpp: what is rteason for line: using pbase_type::rdbuf; \ Doesn't seem needed. _______________________________________________________________ 10. array_stream.hpp: the template template < std::size_t N, typename Ch, class Tr > class basic_array_##SuffixF may contain static assert N > 0. _______________________________________________________________ 11. array_stream.hpp: the constructor template < std::size_t N, typename Ch, class Tr > inline basic_array_streambuf<N, Ch, Tr>::basic_array_streambuf ( typename basic_array_streambuf<N, Ch, Tr>::char_type const * b, typename basic_array_streambuf<N, Ch, Tr>::char_type const * e, std::ios_base::openmode which // = std::ios_base::in | std::ios_base::out ) ... may contain BOOST_ASSERT(b != 0); BOOST_ASSERT(e != 0); _______________________________________________________________ 12. array_stream.hpp: what is reason to use this, e.g. in: return this->gptr() ? ( this->gptr() - this->eback() ) : 0; ? _______________________________________________________________ 13. array_stream.hpp: function seekoff(): shouldn't if ( newindex > off_type(self_type::array_size) ) goto bail; be if ( newindex >= off_type(self_type::array_size) ) goto bail; ? _______________________________________________________________ 14. array_stream.hpp: the InputIterator in template < typename InputIterator > basic_array_streambuf can be 'concept-checked'. _______________________________________________________________ 15. iomanip_form.hpp: in explicit basic_ios_form( ::std::basic_ios<Ch, Tr> const &i ); the parameters really should not be named 'i'. _______________________________________________________________ 16. iomanip_general.hpp: is the declaration: template < typename Ch, class Tr > std::basic_ios<Ch, Tr> & resetios( std::basic_ios<Ch, Tr> &s ); needed? Likewise in iomanip_io.hpp the declaration of - multi_skipl() - skipl() - operator >>() - etc I would prefere smaller file w/o them. _______________________________________________________________ 17. iomanip_general.hpp: operator>>: I find the expression: return s( is ), is; abominable. _______________________________________________________________ 18. streambuf_wrapping.html: some sentences are rather hard to parse: "...checking if the stream buffer's stream switched to an external stream buffer." Maybe its possible to rearrange them so 'stream' and 'buffer' will be less frequent in the text. The term "switching" used here should get explained. _______________________________________________________________ 19. array_stream.html: the documentation should contain some example code snippet. Now it is just source code annotated. _______________________________________________________________ 20 iomanip.html: it should be explained what is "form-based". The documentation should NOT be annotated code, it is very unreadable. Code snippets examples are missing. _______________________________________________________________ 21. naming: the skipl should be named skip_line or so. Current name is extremely annoying for any code maintainer. The fact that endl is in standard doesn't mean cryptic names should be piled up. _______________________________________________________________ 22. value_stream.html: the rationale here is copy of rationale from null_stream.html and completely inapropriate, IMO. _______________________________________________________________ 23. compiling tests on Borland C++ Builder 6.4: -------------------- array_stream_test.cpp: doesn't compile because typedef boost::io::basic_array_streambuf<alphabet_length, char> astreambuf; contains only 2 template parameters instead of required 3. -------------------- iomanip_test_io.hpp: doesn't compile because BCB has problems with the template declarations in iomanip_in/out.hpp. When I commented them out BCB stopped to complain. Failure in: class sync_count_stringbuf { typedef base_type::allocator_type allocator_type; <<== this doesn't compile -------------------- null_stream_test.cpp: null_stream_test.cpp(28): error: namespace "boost::io" has no member "nullbuf" boost::io::nullbuf nb; -------------------- pointer_stream_test.cpp: pointer_stream_test.cpp(31): error: namespace "boost::io" has no member "pointerbuf" boost::io::pointerbuf pb( buffer, buffer + buffer_length ); -------------------- value_stream_test.cpp: value_stream_test.cpp(29): error: namespace "boost::io" has no member "valuebuf" using boost::io::valuebuf; _______________________________________________________________ 24. compiling tests on Intel C++ 7.0 plugged in VC6 IDE: none of the tests compiled, for the same reasons as with BCB. _______________________________________________________________ 25. possible features: there may be more features in library: - 'tee' like output stream, they take data and re-send them all into two other streams - merging input stream which reads data from one stream, when it is exhausted then other stream etc. - in/out stream buffers which adapt some container, e.g. container_ostream<std::vector<char> > - out stream buffer which uses fixed size buffer and if more data are inserted into, then it allocates additional buffer from heap. - 'annotating' out stream, for example adding current time to every data item put in. It may have a functor as parameter and this functor would produce the annotations. - filtering in/out stream which uses binary predicate functor to remove data from stream. _______________________________________________________________ EOF

"Pavel Vozenilek" <pavel_vozenilek@hotmail.com> wrote in message:
25. possible features: there may be more features in library:
I'm planning to write a review of More IO later this week. For now, I'd like to mention that I have an iostreams library up for review later this month or early in September which allows streams and stream buffers to be constructed by combining simple components called Sources, Sinks, InputFilters and OutputFilters. (See http://tinyurl.com/3m6ur) I think this is a better approach than accumulating a bunch of special purpose stream buffers implemented from scratch. I think Daryle's pointer streams and null streams are useful, and may vote for their acceptance, but believe they would be better implemented as Sources and Sinks. Most of your ideas below also fit easily into this framework. For example, using my library, a null_buf and null_ostream can be defined as follows: struct null_sink : boost::io::sink { void write(char*, std::streamsize) { } }; typedef boost::io::streambuf_facade<null_sink> null_buf; typedef boost::io::stream_facade<null_sink> null_ostream; Pointer streams can be defined like so: typedef boost::io::streambuf_facade<boost::io::array_resource> pointerbuf; typedef boost::io::stream_facade<boost::io::array_resource> pointerstream;
- 'tee' like output stream, they take data and re-send them all into two other streams
For this we need to define an OutputFilter which stores a reference to an ostream and has a member function 'write' which forwards all characters to the stored ostream as well as to the downstream sink (you don't need to understand the following code -- the point is that it's just a few lines): struct tee : boost::io::output_filter { tee(std::ostream& dest) : dest(dest) { } template<typename Sink> void write(Sink& snk, char* s, std::streamsize n) { // Write to the downstream Sink boost::io::write(snk, s, n); // Write to the stored ostream: dest.write(s, n); } std::ostream& dest; }; We use the tee as follows. Given two ostreams ostream first; ostream second; we define a filtering_ostream which passes data through the tee to both streams: filtering_ostream out; out.push(tee(first)); out.push(second); out << "this gets written to both ostreams\n"; You can write a tee_ostream deriving from filtering_ostream to hide these details, if you like, but basically all the code is included above.
- merging input stream which reads data from one stream, when it is exhausted then other stream etc.
This is accomplished by the (not yet implemented, but planned :-) ) template template<typename Source1, ... , typename SourceN = default_> class concatenation_view; This is a 'source adapter' which takes a sequence of Sources and returns a Source representing their concatenation. There will be a corresponding object generator boost::io::concatenate, which can be used as follows: filtering_istream in; in.push( concatenate( file_source("file1"), file_source("file2"), file_source("file3") ) ); // read from file1, then file2, then file3, as necessary: char buf[100000]; in.read(buf, 100000);
- in/out stream buffers which adapt some container, e.g. container_ostream<std::vector<char> >
To read from or write to a container, filtering streams can be passed iterator ranges: vector<char> v; .... filtering_ostream out; out.push(v.begin(), v.end()); // Write to v (but be careful not to write past the end). There is also a generic stringstream-like component for accessing an arbitrary container (implemented but not yet working on all platforms): typedef container_resource< vector<char> > vector_resource; typedef streambuf_facade< vector_resource > vectorbuf; The above defines a streambuf which accesses a user-supplied vector<char>, extending it if the user tries to write past the end.
- out stream buffer which uses fixed size buffer and if more data are inserted into, then it allocates additional buffer from heap.
Not hard to implement as a Sink, but I'm not sure I see the advantage over container_resource or std::stringstream.
- 'annotating' out stream, for example adding current time to every data item put in. It may have a functor as parameter and this functor would produce the annotations.
This is a classic OutputFilter. James Kanze, whose work inspired the filtering streams, has an example of this on his website, using basically the same technique as my library. See http://www.gabi-soft.fr/codebase-en.html (TimeStampInserter.hh)
- filtering in/out stream which uses binary predicate functor to remove data from stream.
Here's an InputFilter which filters out characters not satifying a predicate (again, the main point is that it just takes a few lines): template<typename Pred> struct predicate_input_filter : boost::io::input_filter { predicate_input_filter(Pred p) : p(p) { } template<typename Source> int get(Source& src) { int c; while ((c = boost::io::get(src)) != EOF && !p(c)) ; return c; } Pred p; }; We can now read only alphabetic characters from standard input as follows: filtering_istream in; in.push(predicate_input_filter<int(*)(int)>(std::isalpha)); in.push(std::cin); ------- Sorry to go on at such length. My point is that given the proper infrastructure, these ideas can be implemented as fairly lightweight components. Best Regards, Jonathan

"Jonathan Turkanis" wrote:
25. possible features: there may be more features in library:
I'm planning to write a review of More IO later this week. For now, I'd like to mention that I have an iostreams library up for review later this month or early in September which allows streams and stream buffers to be constructed by combining simple components called Sources, Sinks, InputFilters and OutputFilters. (See http://tinyurl.com/3m6ur) I think this is a better approach than accumulating a bunch of special purpose stream buffers implemented from scratch.
I think Daryle's pointer streams and null streams are useful, and may vote for their acceptance, but believe they would be better implemented as Sources and Sinks. Most of your ideas below also fit easily into this framework.
I'm interested and will look into this. /Pavel

"Jonathan Turkanis" <technews@kangaroologic.com> wrote in message news:cgem4t$r20$1@sea.gmane.org...
"Pavel Vozenilek" <pavel_vozenilek@hotmail.com> wrote in message:
- 'tee' like output stream, they take data and re-send them all into two other streams
struct tee : boost::io::output_filter { tee(std::ostream& dest) : dest(dest) { }
template<typename Sink> void write(Sink& snk, char* s, std::streamsize n) { // Write to the downstream Sink boost::io::write(snk, s, n);
// Write to the stored ostream: dest.write(s, n); }
std::ostream& dest; };
Better: struct tee : boost::io::sink { tee(std::ostream& first, std::ostream& second) : first(first), second(second) { } void write(const char* s, std::streamsize n) { first.write(s, n); second.write(s, n); } std::ostream& first; std::ostream& second; }; std::ostream first; std::ostream second; boost::io::stream_facade<tee> out(tee(first, second)); out << "This is simpler and more efficient\n"; Jonathan

| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Jonathan Turkanis | Sent: 24 August 2004 07:19 | To: boost@lists.boost.org | Subject: [boost] Re: Review of Daryle Walker's "More IO" | library beginstoday,August 21, 2004. | I'm planning to write a review of More IO later this week. For now, | I'd like to mention that I have an iostreams library up for review | later this month or early in September which allows streams and stream | buffers to be constructed by combining simple components called | Sources, Sinks, InputFilters and OutputFilters. (See | http://tinyurl.com/3m6ur) This is obviously relevant to Daryle's useful proposals - we need to be sure these two items work together without duplication. Do you have a reference to a way of getting the whole docs (and code?) - for those poor souls in the Dark Ages of a pay per second dailup line? Thanks Paul Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539 561830 +44 7714 330204 mailto: pbristow@hetp.u-net.com

"Paul A Bristow" <pbristow@hetp.u-net.com> wrote in message news:E1BzenJ-0001Lr-00@he200war.uk.vianw.net...
| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Jonathan
Turkanis
| Sent: 24 August 2004 07:19 | To: boost@lists.boost.org | Subject: [boost] Re: Review of Daryle Walker's "More IO" | library beginstoday,August 21, 2004.
| I'm planning to write a review of More IO later this week. For now, | I'd like to mention that I have an iostreams library up for review | later this month or early in September which allows streams and stream | buffers to be constructed by combining simple components called | Sources, Sinks, InputFilters and OutputFilters. (See | http://tinyurl.com/3m6ur)
This is obviously relevant to Daryle's useful proposals - we need to be sure these two items work together without duplication.
Agreed.
Do you have a reference to a way of getting the whole docs (and code?) - for those poor souls in the Dark Ages of a pay per second dailup line?
The link above should allow you to download the entire library as a zip (about 470k) or tar.gz (about 290k). In case the problem is with tinyurl, here's the full link: http://home.comcast.net/~jturkanis/iostreams/ I also put the library in the yahoo files section: http://groups.yahoo.com/group/boost/files/iostream.zip Let me know if there's further trouble. If all else fails I can always send you a hard copy ;-) Jonathan

On 8/24/04 2:18 AM, "Jonathan Turkanis" <technews@kangaroologic.com> wrote: [SNIP]
I think Daryle's pointer streams and null streams are useful, and may vote for their acceptance, but believe they would be better implemented as Sources and Sinks. Most of your ideas below also fit easily into this framework.
For example, using my library, a null_buf and null_ostream can be defined as follows:
struct null_sink : boost::io::sink { void write(char*, std::streamsize) { } }; typedef boost::io::streambuf_facade<null_sink> null_buf; typedef boost::io::stream_facade<null_sink> null_ostream;
Pointer streams can be defined like so:
typedef boost::io::streambuf_facade<boost::io::array_resource> pointerbuf; typedef boost::io::stream_facade<boost::io::array_resource> pointerstream; [TRUNCATE the more complicated ideas]
But why go through all the trouble to forcing an idea through a framework, which is built on top of the Standard I/O framework, when the idea is simple enough to go through the Standard framework directly? -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

"Daryle Walker" <darylew@hotmail.com> wrote in message news:BD55A2D6.E82D%darylew@hotmail.com...
On 8/24/04 2:18 AM, "Jonathan Turkanis" <technews@kangaroologic.com> wrote:
[SNIP]
I think Daryle's pointer streams and null streams are useful, and may vote for their acceptance, but believe they would be better implemented as Sources and Sinks. Most of your ideas below also fit easily into this framework.
For example, using my library, a null_buf and null_ostream can be defined as follows:
struct null_sink : boost::io::sink { void write(char*, std::streamsize) { } }; typedef boost::io::streambuf_facade<null_sink> null_buf; typedef boost::io::stream_facade<null_sink> null_ostream;
Pointer streams can be defined like so:
typedef boost::io::streambuf_facade<boost::io::array_resource> pointerbuf; typedef boost::io::stream_facade<boost::io::array_resource> pointerstream; [TRUNCATE the more complicated ideas]
But why go through all the trouble to forcing an idea through a framework, which is built on top of the Standard I/O framework, when the idea is simple enough to go through the Standard framework directly?
The components, such as null_sink and value_source, are actually *easier* to write than the corresponding stream buffers. They can also be reused in cases where streams and stream buffers are not necessarily the best abstraction. So I don't see this as a case of forcing them into a framework. As sources and sinks they express their core functionality concisely; as stream buffers, the are forced into the 'basic_streambuf framework' with its pecular interface (underflow, uflow overflow, xsgetn, etc, eback, pbase, ....) Jonathan

On 8/28/04 3:36 PM, "Jonathan Turkanis" <technews@kangaroologic.com> wrote:
"Daryle Walker" <darylew@hotmail.com> wrote in message news:BD55A2D6.E82D%darylew@hotmail.com... [SNIP]
But why go through all the trouble to forcing an idea through a framework, which is built on top of the Standard I/O framework, when the idea is simple enough to go through the Standard framework directly?
The components, such as null_sink and value_source, are actually *easier* to write than the corresponding stream buffers. They can also be reused in cases where streams and stream buffers are not necessarily the best abstraction.
When would that ever happen? (More on this in my review of the next Iostreams library.)
So I don't see this as a case of forcing them into a framework. As sources and sinks they express their core functionality concisely; as stream buffers, the are forced into the 'basic_streambuf framework' with its pecular interface (underflow, uflow overflow, xsgetn, etc, eback, pbase, ....)
But they're still forced through two frameworks. The extra indirection isn't worth it (especially since I've gone through your library). -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

On 8/22/04 2:19 PM, "Pavel Vozenilek" <pavel_vozenilek@hotmail.com> wrote:
"tom brinkman" wrote:
The review of Daryle Walker's "More IO" library begins today, August 21, 2004.
I took look on the library. It definitely contains useful functionality, but:
a) its documentation is bad (details bellow) and must be rewritten (or rather actually written),
b) none of tests compiled, due to bugs in code,
c) it may be considered to use inline definitions everywhere instead of out-of-class definitions. It would make code shorter, easier to grok and friendlier to older compilers.
d) more functionality may be considered, see item [25] bellow
e) naming conventions may be reconsidered (see item [5])
I recommend to fix points (a) and (b) first. Then and only then it should be added to Boost, not in current state. (It would not require another full review, IMHO.)
More issues and nitpicks are listed bellow.
/Pavel
_______________________________________________________________ 1. docs: ios_state.html is missing. Dtto ios_state.hpp.
As someone else stated, those are already in Boost. (I just copied the existing "io_fwd.hpp" when creating this one.)
_______________________________________________________________ 2. docs: some introduction into the library would help.
This is a collection of many little libraries; I not sure that a grand introduction could be made.
_______________________________________________________________ 3. docs: source code snippets should be syntax colorized
Even if that's a good idea, these are manually-created HTML files, so you have to wait until some automation is added.
_______________________________________________________________ 4.
#if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif
should be put into each of headers. It has positive effect on VC ad Intel C++ compilation times.
I'm not using Visual C++, Windows, or even a IBM-style PC, so I don't want to go crazy with cross-platform conveniences that I can't check. I do want to know about cross-platform bugs, hopefully with fixes.
_______________________________________________________________ 5. naming conventions: some names as
basic_constpointerbuf
are quite hard to read. Maybe they should
basic_const_pointer_buf
(This is just subjective opinion of me.)
That standard stream (buffer) classes run their name-parts together. (What happened to entry #6?)
_______________________________________________________________ 7. stream_buf_wrapping.hpp: there are three hardcoded constructors like:
template < typename T1, typename T2, typename T3 > basic_wrapping_ios( T1 x1, T2 x2, T3 x3 )
for 1, 2 and 3 parameters though base_from_member supports up to 10 parameters.
I wrote base_from_member, and I extended BFM after initially writing More-I/O.
Boost.Preprocessor can be used here to generate contructors of all available arities.
Any suggestions on how? And should I leave the arity number available in BFM (as a #define) so others can mirror it?
Likewise the basic_wrapping_XYZ bellow.
_______________________________________________________________ 8. stream_buf_wrapping.hpp and others, a nitpick:
The name BOOST_PRIVATE_WRAPPER may be more unique, e.g. BOOST_IO_PRIVATE_WRAPPER to avoid any chance of collision.
_______________________________________________________________ 9. stream_buf_wrapping.hpp: what is rteason for line:
using pbase_type::rdbuf; \
Doesn't seem needed.
The two base classes define different "rdbuf" member functions. That means the subject class needs to explicitly mention which version it'll use.
_______________________________________________________________ 10. array_stream.hpp: the template
template < std::size_t N, typename Ch, class Tr > class basic_array_##SuffixF
may contain static assert N > 0.
A zero-size array will choke the compiler anyway.
_______________________________________________________________ 11. array_stream.hpp: the constructor
template < std::size_t N, typename Ch, class Tr > inline basic_array_streambuf<N, Ch, Tr>::basic_array_streambuf ( typename basic_array_streambuf<N, Ch, Tr>::char_type const * b, typename basic_array_streambuf<N, Ch, Tr>::char_type const * e, std::ios_base::openmode which // = std::ios_base::in | std::ios_base::out ) ...
may contain BOOST_ASSERT(b != 0); BOOST_ASSERT(e != 0);
_______________________________________________________________ 12. array_stream.hpp: what is reason to use this, e.g. in:
return this->gptr() ? ( this->gptr() - this->eback() ) : 0;
?
How else would I get the length of the currently-used get-buffer?
_______________________________________________________________ 13. array_stream.hpp: function seekoff(): shouldn't
if ( newindex > off_type(self_type::array_size) ) goto bail;
be
if ( newindex >= off_type(self_type::array_size) ) goto bail;
?
No. The "off_type(self_type::array_size)" represents the one-past-the-end value. I know it's useless to dereference, just like in iterators, but it needs to be a valid location for other uses.
_______________________________________________________________ 14. array_stream.hpp: the InputIterator in
template < typename InputIterator > basic_array_streambuf
can be 'concept-checked'.
How? And it is worth the extra code? Like other templates, the current code will choke if the given type does not meet the expected interface (although with a nearly-incomprehensible error message).
_______________________________________________________________ 15. iomanip_form.hpp: in
explicit basic_ios_form( ::std::basic_ios<Ch, Tr> const &i );
the parameters really should not be named 'i'.
Why not?
_______________________________________________________________ 16. iomanip_general.hpp: is the declaration:
template < typename Ch, class Tr > std::basic_ios<Ch, Tr> & resetios( std::basic_ios<Ch, Tr> &s );
needed?
Likewise in iomanip_io.hpp the declaration of - multi_skipl() - skipl() - operator >>() - etc
I would prefere smaller file w/o them.
And I like forward-declaring everything.
_______________________________________________________________ 17. iomanip_general.hpp: operator>>: I find the expression:
return s( is ), is;
abominable.
I don't think you have the right filename. Anyway, the code is hard to misinterpret and it saves a line.
_______________________________________________________________ 18. streambuf_wrapping.html: some sentences are rather hard to parse:
"...checking if the stream buffer's stream switched to an external stream buffer."
Maybe its possible to rearrange them so 'stream' and 'buffer' will be less frequent in the text.
The term "switching" used here should get explained.
_______________________________________________________________ 19. array_stream.html: the documentation should contain some example code snippet. Now it is just source code annotated.
_______________________________________________________________ 20 iomanip.html: it should be explained what is "form-based".
The documentation should NOT be annotated code, it is very unreadable.
What do you mean by that? I've tried to imitate the Standard's way of describing items. Anyway, it's hard to be precise about the actions/effects without getting close to code when the functions are simple.
Code snippets examples are missing.
_______________________________________________________________ 21. naming: the skipl should be named skip_line or so. Current name is extremely annoying for any code maintainer.
The fact that endl is in standard doesn't mean cryptic names should be piled up.
_______________________________________________________________ 22. value_stream.html: the rationale here is copy of rationale from null_stream.html and completely inapropriate, IMO.
_______________________________________________________________ 23. compiling tests on Borland C++ Builder 6.4:
-------------------- array_stream_test.cpp: doesn't compile because typedef boost::io::basic_array_streambuf<alphabet_length, char> astreambuf;
contains only 2 template parameters instead of required 3.
-------------------- iomanip_test_io.hpp: doesn't compile because BCB has problems with the template declarations in iomanip_in/out.hpp. When I commented them out BCB stopped to complain.
Failure in: class sync_count_stringbuf { typedef base_type::allocator_type allocator_type; <<== this doesn't compile
-------------------- null_stream_test.cpp:
null_stream_test.cpp(28): error: namespace "boost::io" has no member "nullbuf" boost::io::nullbuf nb;
-------------------- pointer_stream_test.cpp:
pointer_stream_test.cpp(31): error: namespace "boost::io" has no member "pointerbuf" boost::io::pointerbuf pb( buffer, buffer + buffer_length );
-------------------- value_stream_test.cpp:
value_stream_test.cpp(29): error: namespace "boost::io" has no member "valuebuf" using boost::io::valuebuf;
_______________________________________________________________ 24. compiling tests on Intel C++ 7.0 plugged in VC6 IDE: none of the tests compiled, for the same reasons as with BCB.
[This response is also for #23.] All my stuff compiles for me. If you can figure out what compiler quirks (or mistakes on my part) are causing the problem, let me know.
_______________________________________________________________ 25. possible features: there may be more features in library:
- 'tee' like output stream, they take data and re-send them all into two other streams
- merging input stream which reads data from one stream, when it is exhausted then other stream etc.
- in/out stream buffers which adapt some container, e.g. container_ostream<std::vector<char> >
- out stream buffer which uses fixed size buffer and if more data are inserted into, then it allocates additional buffer from heap.
- 'annotating' out stream, for example adding current time to every data item put in. It may have a functor as parameter and this functor would produce the annotations.
- filtering in/out stream which uses binary predicate functor to remove data from stream.
All the example stream in the library so far have one thing in common: they are based off the CORE language. These requests could be based off the standard library. Those can come later, or may be supplied by the upcoming for review "The Boost Iostreams Library" by Jonathan D. Turkanis. Most of the items here aren't big in the grand scheme of all C++. The pointer-based streams are very important, however, as they allow existing memory blocks to be used, finishing the legacy of std::strstream that std::stringstream left unfinished. -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

"Daryle Walker" <darylew@hotmail.com> wrote:
On 8/22/04 2:19 PM, "Pavel Vozenilek" <pavel_vozenilek@hotmail.com> wrote:
______________________________________________________________
7. stream_buf_wrapping.hpp: there are three hardcoded constructors like:
template < typename T1, typename T2, typename T3 > basic_wrapping_ios( T1 x1, T2 x2, T3 x3 )
for 1, 2 and 3 parameters though base_from_member supports up to 10 parameters.
I wrote base_from_member, and I extended BFM after initially writing More-I/O.
Boost.Preprocessor can be used here to generate contructors of all available arities.
Any suggestions on how? And should I leave the arity number available in BFM (as a #define) so others can mirror it?
I've attached a version of base_from_member.hpp with configurable maximum arity, defaulting to 10. If you need higher arity, you #define BOOST_BASE_FROM_MEMBER_MAX_ARITY to an appropriate value before including the header. The same technique will work for streambuf wrapping. Jonathan begin 666 base_from_member.hpp M+R\@(&)O;W-T('5T:6QI='DO8F%S95]F<F]M7VUE;6)E<BYH<' @:&5A9&5R M(&9I;&4@("TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+R\-"@T*+R\@($-O M<'ER:6=H=" R,# Q+" R,# S($1A<GEL92!786QK97(N("!5<V4L(&UO9&EF M:6-A=&EO;BP@86YD(&1I<W1R:6)U=&EO;B!A<F4-"B\O("!S=6)J96-T('1O M('1H92!";V]S="!3;V9T=V%R92!,:6-E;G-E+"!697)S:6]N(#$N,"X@("A3 M964@86-C;VUP86YY:6YG(&9I;&4-"B\O("!,24-%3E-%7S%?,"YT>'0@;W(@ M82!C;W!Y(&%T(#QH='1P.B\O=W=W+F)O;W-T+F]R9R],24-%3E-%7S%?,"YT M>'0^+BD-"@T*+R\@(%-E92 \:'1T<#HO+W=W=RYB;V]S="YO<F<O;&EB<R]U M=&EL:71Y+SX@9F]R('1H92!L:6)R87)Y)W,@:&]M92!P86=E+@T*#0HO+R P M."TR-RTP-#H@2F]N871H86X@5'5R:V%N:7,@;6%D92!M87AI;75M(&%R:71Y M(&-O;F9I9W5R86)L92X-"@T*(VEF;F1E9B!"3T]35%]55$E,25197T)!4T5? M1E)/35]-14U"15)?2%!0#0HC9&5F:6YE($)/3U-47U5424Q)5%E?0D%315]& M4D]-7TU%34)%4E](4% -"@T*(VEN8VQU9&4@/&)O;W-T+W5T:6QI='E?9G=D M+FAP<#X@("\O(')E<75I<F5D(&9O<B!P87)A;65T97(@9&5F875L=',-"B-I M;F-L=61E(#QB;V]S="]P<F5P<F]C97-S;W(O87)I=&AM971I8R]I;F,N:'!P M/@T*(VEN8VQU9&4@/&)O;W-T+W!R97!R;V-E<W-O<B]R97!E=&ET:6]N+V5N M=6U?<&%R86US+FAP<#X-"B-I;F-L=61E(#QB;V]S="]P<F5P<F]C97-S;W(O M<F5P971I=&EO;B]E;G5M7V)I;F%R>5]P87)A;7,N:'!P/@T*(VEN8VQU9&4@ M/&)O;W-T+W!R97!R;V-E<W-O<B]R97!E=&ET:6]N+W)E<&5A=%]F<F]M7W1O M+FAP<#X-"@T*+R\@0V]N9FEG=7)A8FQE(&UA>&EM=6T@8V]N<W1R=6-T;W(@ M87)I='D-"B-I9FYD968@0D]/4U1?0D%315]&4D]-7TU%34)%4E]-05A?05)) M5%D-"B,@9&5F:6YE($)/3U-47T)!4T5?1E)/35]-14U"15)?34%87T%22519 M(#$P#0HC96YD:68-"@T*+R\-"B\O($UA8W)O(&YA;64Z($)/3U-47T-/3E-4 M4E5#5$]27T1%1BAZ+"!N+"!D871A*0T*+R\@1&5S8W)I<'1I;VXZ($5X<&%N M9',@=&\-"B\O#0HO+R @("!T96UP;&%T93P@='EP96YA;64@5#$L("XN+BP@ M='EP96YA;64@5&X@/@T*+R\@(" @8F%S95]F<F]M7VUE;6)E<B@@5#$@>#$L M("XN+BP@5&X@>&X@*0T*+R\@(" @(" @(#H@;65M8F5R*"!X,2P@+BXN+"!X M;B I#0HO+R @(" @(" @>WT-"B\O#0HO+R!.;W1E.B C=6YD968G9"!B96QO M=RX-"B\O#0HC9&5F:6YE($)/3U-47T-/3E-44E5#5$]27T1%1BAZ+"!N+"!D M871A*2 @(" @(" @(" @(" @(" @(" @(" @(" @(%P-"B @("!T96UP;&%T M93Q"3T]35%]04%]%3E5-7U!!4D%-4RAN+"!T>7!E;F%M92!4*3X@(" @(" @ M(" @(" @(" @(" @7 T*(" @(&5X<&QI8VET(&)A<V5?9G)O;5]M96UB97(H M0D]/4U1?4%!?14Y535]"24Y!4EE?4$%204U3*&XL(%0L('@I*2!<#0H@(" @ M(" @(" Z(&UE;6)E<BA"3T]35%]04%]%3E5-7U!!4D%-4RAN+"!X*2D@>R!] M(" @(" @(" @(" @(" @(" @(%P-"B @(" O*BHO#0H-"FYA;65S<&%C92!B M;V]S= T*>PT*#0HO+R @0F%S92UF<F]M+6UE;6)E<B!C;&%S<R!T96UP;&%T M92 @+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TO M+PT*#0HO+R!(96QP97(@=&\@:6YI=&EA;&EZ92!A(&)A<V4@;V)J96-T('-O M(&$@9&5R:79E9"!C;&%S<R!C86X@=7-E('1H:7,-"B\O(&]B:F5C="!I;B!T M:&4@:6YI=&EA;&EZ871I;VX@;V8@86YO=&AE<B!B87-E(&-L87-S+B @57-E M9"!B>0T*+R\@1&EE=&UA<B!+=65H;"!F<F]M(&ED96%S(&)Y(%)O;B!+;&%T M8VAO('1O('-O;'9E('1H92!P<F]B;&5M(&]F(&$-"B\O(&)A<V4@8VQA<W,@ M;F5E9&EN9R!T;R!B92!I;FET:6%L:7IE9"!B>2!A(&UE;6)E<BX-"@T*+R\@ M0V]N=')I8G5T960@8GD@1&%R>6QE(%=A;&ME<@T*#0IT96UP;&%T92 \('1Y M<&5N86UE($UE;6)E<E1Y<&4L(&EN="!5;FEQ=65)1" ^#0IC;&%S<R!B87-E M7V9R;VU?;65M8F5R#0I[#0IP<F]T96-T960Z#0H@(" @365M8F5R5'EP92 @ M;65M8F5R.PT*#0H@(" @8F%S95]F<F]M7VUE;6)E<B@I#0H@(" @(" @(#H@ M;65M8F5R*"D-"B @(" @(" @>WT-"@T*(" @($)/3U-47U!07U)%4$5!5%]& M4D]-7U1/* T*(" @(" @(" Q+"!"3T]35%]04%])3D,H0D]/4U1?0D%315]& M4D]-7TU%34)%4E]-05A?05))5%DI+ T*(" @(" @("!"3T]35%]#3TY35%)5 M0U1/4E]$148L(%\-"B @(" I#0H-"GT[(" O+R!B;V]S=#HZ8F%S95]F<F]M M7VUE;6)E<@T*#0I](" O+R!N86UE<W!A8V4@8F]O<W0-"@T*(W5N9&5F($)/ M3U-47T-/3E-44E5#5$]27T1%1@T*#0HC96YD:68@("\O($)/3U-47U5424Q) 75%E?0D%315]&4D]-7TU%34)%4E](4% ` ` end

7. stream_buf_wrapping.hpp: there are three hardcoded constructors like:
template < typename T1, typename T2, typename T3 > basic_wrapping_ios( T1 x1, T2 x2, T3 x3 )
for 1, 2 and 3 parameters though base_from_member supports up to 10 parameters.
I wrote base_from_member, and I extended BFM after initially writing More-I/O.
Boost.Preprocessor can be used here to generate contructors of all available arities.
Any suggestions on how? And should I leave the arity number available in BFM (as a #define) so others can mirror it?
I've attached a version of base_from_member.hpp with configurable maximum arity, defaulting to 10. If you need higher arity, you #define BOOST_BASE_FROM_MEMBER_MAX_ARITY to an appropriate value before including
"Jonathan Turkanis" wrote: ______________________________________________________________ the
header.
The same technique will work for streambuf wrapping.
It may be better to use local iteration technique. Some preprocessors (e.g. BCB) have quite low limit on length of expanded macro (BCB has some 1-2kB). Local iteration is also faster on EDG based frontends. For base-from-member it is probably safe but streamsbufs may be harder. /Pavel

On 8/28/04 4:25 AM, "Pavel Vozenilek" <pavel_vozenilek@hotmail.com> wrote:
"Jonathan Turkanis" wrote: [SNIP]
I've attached a version of base_from_member.hpp with configurable maximum arity, defaulting to 10. If you need higher arity, you #define BOOST_BASE_FROM_MEMBER_MAX_ARITY to an appropriate value before including the header.
The same technique will work for streambuf wrapping.
It may be better to use local iteration technique. Some preprocessors (e.g. BCB) have quite low limit on length of expanded macro (BCB has some 1-2kB).
Local iteration is also faster on EDG based frontends.
Do you have an example of this alternate technique? (Or at least what I should look up.)
For base-from-member it is probably safe but streamsbufs may be harder.
-- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

On 8/28/04 4:25 AM, "Pavel Vozenilek" <pavel_vozenilek@hotmail.com> wrote:
"Jonathan Turkanis" wrote: [SNIP]
I've attached a version of base_from_member.hpp with configurable maximum arity, defaulting to 10. If you need higher arity, you #define BOOST_BASE_FROM_MEMBER_MAX_ARITY to an appropriate value before including
"Daryle Walker" <darylew@hotmail.com> wrote in message news:BD58038C.E8DE%darylew@hotmail.com... the
header.
The same technique will work for streambuf wrapping.
It may be better to use local iteration technique. Some preprocessors (e.g. BCB) have quite low limit on length of expanded macro (BCB has some 1-2kB).
Local iteration is also faster on EDG based frontends.
Do you have an example of this alternate technique? (Or at least what I should look up.)
Hi Daryle, I believe the attached file does what Pavel has in mind. Let someone else check it, though, since I'm not preprocessor expert. Jonathan begin 666 base_from_member.hpp M+R\@(&)O;W-T('5T:6QI='DO8F%S95]F<F]M7VUE;6)E<BYH<' @:&5A9&5R M(&9I;&4@("TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+R\-"@T*+R\@($-O M<'ER:6=H=" R,# Q+" R,# S+" R,# T($1A<GEL92!786QK97(N("!5<V4L M(&UO9&EF:6-A=&EO;BP@86YD#0HO+R @9&ES=')I8G5T:6]N(&%R92!S=6)J M96-T('1O('1H92!";V]S="!3;V9T=V%R92!,:6-E;G-E+"!697)S:6]N(#$N M,"X@("A3964-"B\O("!A8V-O;7!A;GEI;F<@9FEL92!,24-%3E-%7S%?,"YT M>'0@;W(@82!C;W!Y(&%T#0HO+R @/&AT=' Z+R]W=W<N8F]O<W0N;W)G+TQ) M0T5.4T5?,5\P+G1X=#XN*0T*#0HO+R @4V5E(#QH='1P.B\O=W=W+F)O;W-T M+F]R9R]L:6)S+W5T:6QI='DO/B!F;W(@=&AE(&QI8G)A<GDG<R!H;VUE('!A M9V4N#0H-"B-I9FYD968@0D]/4U1?551)3$E465]"05-%7T923TU?345-0D52 M7TA04 T*(V1E9FEN92!"3T]35%]55$E,25197T)!4T5?1E)/35]-14U"15)? M2%!0#0H-"B-I;F-L=61E(#QB;V]S="]P<F5P<F]C97-S;W(O87)I=&AM971I M8R]I;F,N:'!P/@T*(VEN8VQU9&4@/&)O;W-T+W!R97!R;V-E<W-O<B]R97!E M=&ET:6]N+V5N=6U?8FEN87)Y7W!A<F%M<RYH<' ^#0HC:6YC;'5D92 \8F]O M<W0O<')E<')O8V5S<V]R+W)E<&5T:71I;VXO96YU;5]P87)A;7,N:'!P/@T* M#0HO+R @0F%S92UF<F]M+6UE;6)E<B!A<FET>2!C;VYF:6=U<F%T:6]N(&UA M8W)O(" M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TO+PT*#0HO+R!4 M:&4@9F]L;&]W:6YG(&UA8W)O(&1E=&5R;6EN97,@:&]W(&UA;GD@87)G=6UE M;G1S('=I;&P@8F4@:6X@=&AE(&QA<F=E<W0-"B\O(&-O;G-T<G5C=&]R('1E M;7!L871E(&]F(&)A<V5?9G)O;5]M96UB97(N("!#;VYS=')U8W1O<B!T96UP M;&%T97,@=VEL;"!B90T*+R\@9V5N97)A=&5D(&9R;VT@;VYE(&%R9W5M96YT M('1O('1H:7,@;6%X:6UU;2X@($-O9&4@9G)O;2!O=&AE<B!F:6QE<R!C86X@ M<F5A9 T*+R\@=&AI<R!N=6UB97(@:68@=&AE>2!N965D('1O(&%L=V%Y<R!M M871C:"!T:&4@97AA8W0@;6%X:6UU;2!B87-E7V9R;VU?;65M8F5R#0HO+R!U M<V5S+B @5&AE(&UA>&EM=6T@8V]N<W1R=6-T;W(@;&5N9W1H(&-A;B!B92!C M:&%N9V5D(&)Y(&]V97)R:61I;F<@=&AE#0HO+R C9&5F:6YE9"!C;VYS=&%N M="X@($UA:V4@<W5R92!T;R!A<'!L>2!T:&4@;W9E<G)I9&4L(&EF(&%N>2P@ M9F]R(&%L;"!S;W5R8V4-"B\O(&9I;&5S(&1U<FEN9R!P<F]J96-T(&-O;7!I M;&EN9R!F;W(@8V]N<VES=&5N8WDN#0H-"B\O($-O;G1R:6)U=&5D(&)Y($IO M;F%T:&%N(%1U<FMA;FES#0H-"B-I9FYD968@0D]/4U1?0D%315]&4D]-7TU% M34)%4E]-05A?05))5%D-"B-D969I;F4@0D]/4U1?0D%315]&4D]-7TU%34)% M4E]-05A?05))5%D@(#$P#0HC96YD:68-"@T*#0HO+R @06X@:71E<F%T:6]N M(&]F(&$@8V]N<W1R=6-T;W(@=&5M<&QA=&4@9F]R(&)A<V5?9G)O;5]M96UB M97(@("TM+2TM+2TM+2TM+2TO+PT*#0HO+R!!(&UA8W)O('1H870@<VAO=6QD M(&5X<&%N9"!T;SH-"B\O(" @("!T96UP;&%T92 \('1Y<&5N86UE(%0Q+" N M+BXL('1Y<&5N86UE(%1N(#X-"B\O(" @("!B87-E7V9R;VU?;65M8F5R*"!4 M,2!X,2P@+BXN+"!4;B!X;B I#0HO+R @(" @(" @(#H@;65M8F5R*"!X,2P@ M+BXN+"!X;B I#0HO+R @(" @(" @('M]#0HO+R!4:&ES(&UA8W)O('-H;W5L M9"!O;FQY('!E<G-I<W0@=VET:&EN('1H:7,@9FEL92X-"@T*(V1E9FEN92!" M3T]35%]04DE6051%7T-44E]$148H(&X@*2 @(" @(" @(" @(" @(" @(" @ M(" @(" @(" @(" @(" @("!<#0H@(" @=&5M<&QA=&4@/"!"3T]35%]04%]% M3E5-7U!!4D%-4RAN+"!T>7!E;F%M92!4*2 ^(" @(" @(" @(" @(" @(" @ M(%P-"@EE>'!L:6-I="!B87-E7V9R;VU?;65M8F5R*"!"3T]35%]04%]%3E5- M7T))3D%265]005)!35,H;BP@5"P@>"D@*2 @7 T*"2 @(" Z(&UE;6)E<B@@ M0D]/4U1?4%!?14Y535]005)!35,H;BP@>"D@*2 @(" @(" @(" @(" @(" @ M(" @(" @("!<#0H)"7M](" @(" @(" @(" @(" @(" @(" @(" @(" @(" @ M(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @(%P-"@DO*BHO#0H-"FYA M;65S<&%C92!B;V]S= T*>PT*#0HO+R @0F%S92UF<F]M+6UE;6)E<B!C;&%S M<R!T96UP;&%T92 @+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM M+2TM+2TM+2TO+PT*#0HO+R!(96QP97(@=&\@:6YI=&EA;&EZ92!A(&)A<V4@ M;V)J96-T('-O(&$@9&5R:79E9"!C;&%S<R!C86X@=7-E('1H:7,-"B\O(&]B M:F5C="!I;B!T:&4@:6YI=&EA;&EZ871I;VX@;V8@86YO=&AE<B!B87-E(&-L M87-S+B @57-E9"!B>0T*+R\@1&EE=&UA<B!+=65H;"!F<F]M(&ED96%S(&)Y M(%)O;B!+;&%T8VAO('1O('-O;'9E('1H92!P<F]B;&5M(&]F(&$-"B\O(&)A M<V4@8VQA<W,@;F5E9&EN9R!T;R!B92!I;FET:6%L:7IE9"!B>2!A(&UE;6)E M<BX-"@T*+R\@0V]N=')I8G5T960@8GD@1&%R>6QE(%=A;&ME<@T*#0IT96UP M;&%T92 \('1Y<&5N86UE($UE;6)E<E1Y<&4L(&EN="!5;FEQ=65)1" ](# @ M/@T*8VQA<W,@8F%S95]F<F]M7VUE;6)E<@T*>PT*<')O=&5C=&5D.@T*(" @ M($UE;6)E<E1Y<&4@(&UE;6)E<CL-"@T*(" @(&)A<V5?9G)O;5]M96UB97(H M*0T*(" @(" @(" Z(&UE;6)E<B@I#0H@(" @(" @('M]#0H-"B-I9B A0D]/ M4U1?4%!?25-?251%4D%424Y'#0HC(&EN8VQU9&4@/&)O;W-T+W!R97!R;V-E M<W-O<B]I=&5R871I;VXO:71E<F%T92YH<' ^#0HC(&1E9FEN92!"3T]35%]0 M4%]&24Q%3D%-15\Q(#QB;V]S="]U=&EL:71Y+V)A<V5?9G)O;5]M96UB97(N M:'!P/@T*(R!D969I;F4@0D]/4U1?4%!?251%4D%424].7TQ)34E44R H,"P@ M0D]/4U1?0D%315]&4D]-7TU%34)%4E]-05A?05))5%DI#0HC(&EN8VQU9&4@ M0D]/4U1?4%!?251%4D%412@I#0HC96YD:68-"@T*?3L@+R\@8F]O<W0Z.F)A M<V5?9G)O;5]M96UB97(-"@T*?2 @+R\@;F%M97-P86-E(&)O;W-T#0H-"B\O M(%5N9&\@86YY('!R:79A=&4@;6%C<F]S#0HC=6YD968@0D]/4U1?4%))5D%4 M15]#5%)?1$5H-"B-E;F1I9B @+R\@0D]/4U1?551)3$E465]"05-%7T92 M3TU?345-0D527TA04 T*#0HC:68@0D]/4U1?4%!?25-?251%4D%424Y'#0H@ M(" @0D]/4U1?4%))5D%415]#5%)?1$5&*$)/3U-47U!07TE.0RA"3T]35%]0 94%])5$52051)3TXH*2DI#0HC96YD:68-"@`` ` end

"Jonathan Turkanis" <technews@kangaroologic.com> wrote:
I believe the attached file does what Pavel has in mind. Let someone else check it, though, since I'm not preprocessor expert.
One last try ... the version I just posted had the include guards out of order. Jonathan begin 666 base_from_member.hpp M+R\@(&)O;W-T('5T:6QI='DO8F%S95]F<F]M7VUE;6)E<BYH<' @:&5A9&5R M(&9I;&4@("TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+R\-"@T*+R\@($-O M<'ER:6=H=" R,# Q+" R,# S+" R,# T($1A<GEL92!786QK97(N("!5<V4L M(&UO9&EF:6-A=&EO;BP@86YD#0HO+R @9&ES=')I8G5T:6]N(&%R92!S=6)J M96-T('1O('1H92!";V]S="!3;V9T=V%R92!,:6-E;G-E+"!697)S:6]N(#$N M,"X@("A3964-"B\O("!A8V-O;7!A;GEI;F<@9FEL92!,24-%3E-%7S%?,"YT M>'0@;W(@82!C;W!Y(&%T#0HO+R @/&AT=' Z+R]W=W<N8F]O<W0N;W)G+TQ) M0T5.4T5?,5\P+G1X=#XN*0T*#0HO+R @4V5E(#QH='1P.B\O=W=W+F)O;W-T M+F]R9R]L:6)S+W5T:6QI='DO/B!F;W(@=&AE(&QI8G)A<GDG<R!H;VUE('!A M9V4N#0H-"B-I9FYD968@0D]/4U1?551)3$E465]"05-%7T923TU?345-0D52 M7TA04" O+R!);F-L=61E(&=U87)D(&1E9FEN960@8F5L;W<-"B-I9B A0D]/ M4U1?4%!?25-?251%4D%424Y'#0H-"B-I;F-L=61E(#QB;V]S="]P<F5P<F]C M97-S;W(O87)I=&AM971I8R]I;F,N:'!P/@T*(VEN8VQU9&4@/&)O;W-T+W!R M97!R;V-E<W-O<B]R97!E=&ET:6]N+V5N=6U?8FEN87)Y7W!A<F%M<RYH<' ^ M#0HC:6YC;'5D92 \8F]O<W0O<')E<')O8V5S<V]R+W)E<&5T:71I;VXO96YU M;5]P87)A;7,N:'!P/@T*#0HO+R @0F%S92UF<F]M+6UE;6)E<B!A<FET>2!C M;VYF:6=U<F%T:6]N(&UA8W)O(" M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM M+2TM+2TO+PT*#0HO+R!4:&4@9F]L;&]W:6YG(&UA8W)O(&1E=&5R;6EN97,@ M:&]W(&UA;GD@87)G=6UE;G1S('=I;&P@8F4@:6X@=&AE(&QA<F=E<W0-"B\O M(&-O;G-T<G5C=&]R('1E;7!L871E(&]F(&)A<V5?9G)O;5]M96UB97(N("!# M;VYS=')U8W1O<B!T96UP;&%T97,@=VEL;"!B90T*+R\@9V5N97)A=&5D(&9R M;VT@;VYE(&%R9W5M96YT('1O('1H:7,@;6%X:6UU;2X@($-O9&4@9G)O;2!O M=&AE<B!F:6QE<R!C86X@<F5A9 T*+R\@=&AI<R!N=6UB97(@:68@=&AE>2!N M965D('1O(&%L=V%Y<R!M871C:"!T:&4@97AA8W0@;6%X:6UU;2!B87-E7V9R M;VU?;65M8F5R#0HO+R!U<V5S+B @5&AE(&UA>&EM=6T@8V]N<W1R=6-T;W(@ M;&5N9W1H(&-A;B!B92!C:&%N9V5D(&)Y(&]V97)R:61I;F<@=&AE#0HO+R C M9&5F:6YE9"!C;VYS=&%N="X@($UA:V4@<W5R92!T;R!A<'!L>2!T:&4@;W9E M<G)I9&4L(&EF(&%N>2P@9F]R(&%L;"!S;W5R8V4-"B\O(&9I;&5S(&1U<FEN M9R!P<F]J96-T(&-O;7!I;&EN9R!F;W(@8V]N<VES=&5N8WDN#0H-"B\O($-O M;G1R:6)U=&5D(&)Y($IO;F%T:&%N(%1U<FMA;FES#0H-"B-I9FYD968@0D]/ M4U1?0D%315]&4D]-7TU%34)%4E]-05A?05))5%D-"B-D969I;F4@0D]/4U1? M0D%315]&4D]-7TU%34)%4E]-05A?05))5%D@(#$P#0HC96YD:68-"@T*+R\@ M($%N(&ET97)A=&EO;B!O9B!A(&-O;G-T<G5C=&]R('1E;7!L871E(&9O<B!B M87-E7V9R;VU?;65M8F5R(" M+2TM+2TM+2TM+2TM+R\-"@T*+R\@02!M86-R M;R!T:&%T('-H;W5L9"!E>'!A;F0@=&\Z#0HO+R @(" @=&5M<&QA=&4@/"!T M>7!E;F%M92!4,2P@+BXN+"!T>7!E;F%M92!4;B ^#0HO+R @(" @8F%S95]F M<F]M7VUE;6)E<B@@5#$@>#$L("XN+BP@5&X@>&X@*0T*+R\@(" @(" @(" Z M(&UE;6)E<B@@>#$L("XN+BP@>&X@*0T*+R\@(" @(" @("![?0T*+R\@5&AI M<R!M86-R;R!S:&]U;&0@;VYL>2!P97)S:7-T('=I=&AI;B!T:&ES(&9I;&4N M#0H-"B-D969I;F4@0D]/4U1?4%))5D%415]#5%)?1$5&*"!N("D@(" @(" @ M(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @7 T*(" @('1E;7!L871E M(#P@0D]/4U1?4%!?14Y535]005)!35,H;BP@='EP96YA;64@5"D@/B @(" @ M(" @(" @(" @(" @("!<#0H)97AP;&EC:70@8F%S95]F<F]M7VUE;6)E<B@@ M0D]/4U1?4%!?14Y535]"24Y!4EE?4$%204U3*&XL(%0L('@I("D@(%P-"@D@ M(" @.B!M96UB97(H($)/3U-47U!07T5.54U?4$%204U3*&XL('@I("D@(" @ M(" @(" @(" @(" @(" @(" @(" @7 T*"0E[?2 @(" @(" @(" @(" @(" @ M(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @(" @("!< M#0H)+RHJ+PT*#0IN86UE<W!A8V4@8F]O<W0-"GL-"@T*+R\@($)A<V4M9G)O M;2UM96UB97(@8VQA<W,@=&5M<&QA=&4@("TM+2TM+2TM+2TM+2TM+2TM+2TM M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+R\-"@T*+R\@2&5L<&5R('1O(&EN:71I M86QI>F4@82!B87-E(&]B:F5C="!S;R!A(&1E<FEV960@8VQA<W,@8V%N('5S M92!T:&ES#0HO+R!O8FIE8W0@:6X@=&AE(&EN:71I86QI>F%T:6]N(&]F(&%N M;W1H97(@8F%S92!C;&%S<RX@(%5S960@8GD-"B\O($1I971M87(@2W5E:&P@ M9G)O;2!I9&5A<R!B>2!2;VX@2VQA=&-H;R!T;R!S;VQV92!T:&4@<')O8FQE M;2!O9B!A#0HO+R!B87-E(&-L87-S(&YE961I;F<@=&\@8F4@:6YI=&EA;&EZ M960@8GD@82!M96UB97(N#0H-"B\O($-O;G1R:6)U=&5D(&)Y($1A<GEL92!7 M86QK97(-"@T*=&5M<&QA=&4@/"!T>7!E;F%M92!-96UB97)4>7!E+"!I;G0@ M56YI<75E240@/2 P(#X-"F-L87-S(&)A<V5?9G)O;5]M96UB97(-"GL-"G!R M;W1E8W1E9#H-"B @("!-96UB97)4>7!E("!M96UB97([#0H-"B @("!B87-E M7V9R;VU?;65M8F5R*"D-"B @(" @(" @.B!M96UB97(H*0T*(" @(" @("![ M?0T*#0HC:6YC;'5D92 \8F]O<W0O<')E<')O8V5S<V]R+VET97)A=&EO;B]I M=&5R871E+FAP<#X-"B-D969I;F4@0D]/4U1?4%!?1DE,14Y!345?,2 \8F]O M<W0O=71I;&ET>2]B87-E7V9R;VU?;65M8F5R+FAP<#X-"B-D969I;F4@0D]/ M4U1?4%!?251%4D%424].7TQ)34E44R H,"P@0D]/4U1?0D%315]&4D]-7TU% M34)%4E]-05A?05))5%DI#0HC:6YC;'5D92!"3T]35%]04%])5$52051%*"D- M"@T*?3L@+R\@8F]O<W0Z.F)A<V5?9G)O;5]M96UB97(-"@T*?2 @+R\@;F%M M97-P86-E(&)O;W-T#0H-"B\O(%5N9&\@86YY('!R:79A=&4@;6%C<F]S(&%N M9"!D969I;F4@:6YC;'5D92!G=6%R9 T*(W5N9&5F($)/3U-47U!2259!5$5? M0U127T1%1@T*(V1E9FEN92!"3T]35%]55$E,25197T)!4T5?1E)/35]-14U" M15)?2%!0#0H-"B-E;'-E("\O($)/3U-47U!07TE37TE415)!5$E.1PT*(" @ M($)/3U-47U!2259!5$5?0U127T1%1BA"3T]35%]04%])3D,H0D]/4U1?4%!? M251%4D%424].*"DI*0T*(V5N9&EF("\O($)/3U-47U!07TE37TE415)!5$E. M1PT*(V5N9&EF("\O($)/3U-47U5424Q)5%E?0D%315]&4D]-7TU%34)%4E]( $4% -"@`` ` end

"Jonathan Turkanis" wrote:
I believe the attached file does what Pavel has in mind. Let someone
else
check it, though, since I'm not preprocessor expert.
One last try ... the version I just posted had the include guards out of order.
The technique used here is called file iteration. It works well. It is the most powerful mechanism in PP. The local iteration approach is bit simpler and would look like: ------------- #define BOOST_PP_LOCAL_MACRO( n ) \ template < BOOST_PP_ENUM_PARAMS(n, typename T) > \ explicit base_from_member( BOOST_PP_ENUM_BINARY_PARAMS(n, T, x) ) \ : member( BOOST_PP_ENUM_PARAMS(n, x) ) \ {} \ /**/ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_BASE_FROM_MEMBER_MAX_ARITY) #include BOOST_PP_LOCAL_ITERATE() ------------- I think file iteration makes no harm. /Pavel

"Pavel Vozenilek" <pavel_vozenilek@hotmail.com> writes:
"Jonathan Turkanis" wrote:
I believe the attached file does what Pavel has in mind. Let someone
else
check it, though, since I'm not preprocessor expert.
One last try ... the version I just posted had the include guards out of order.
The technique used here is called file iteration. It works well.
Actually that's called "local iteration".
It is the most powerful mechanism in PP.
That's debatable, I guess ;-). It is cool, though.
The local iteration approach is bit simpler and would look like: ------------- #define BOOST_PP_LOCAL_MACRO( n ) \ template < BOOST_PP_ENUM_PARAMS(n, typename T) > \ explicit base_from_member( BOOST_PP_ENUM_BINARY_PARAMS(n, T, x) ) \ : member( BOOST_PP_ENUM_PARAMS(n, x) ) \ {} \ /**/
#define BOOST_PP_LOCAL_LIMITS (1, BOOST_BASE_FROM_MEMBER_MAX_ARITY) #include BOOST_PP_LOCAL_ITERATE() -------------
I think file iteration makes no harm.
/Pavel
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"Pavel Vozenilek" <pavel_vozenilek@hotmail.com> wrote in message news:cgvjfh$arq$1@sea.gmane.org...
"Jonathan Turkanis" wrote:
I believe the attached file does what Pavel has in mind. Let someone
else
check it, though, since I'm not preprocessor expert.
The local iteration approach is bit simpler and would look like: ------------- #define BOOST_PP_LOCAL_MACRO( n ) \ template < BOOST_PP_ENUM_PARAMS(n, typename T) > \ explicit base_from_member( BOOST_PP_ENUM_BINARY_PARAMS(n, T, x) ) \ : member( BOOST_PP_ENUM_PARAMS(n, x) ) \ {} \ /**/
#define BOOST_PP_LOCAL_LIMITS (1, BOOST_BASE_FROM_MEMBER_MAX_ARITY) #include BOOST_PP_LOCAL_ITERATE() -------------
Thank's, Pavel. I find the preprocessor library fascinating but hard to learn since the basic techniques and terminology are not explained very well in the documentation, and I don't have the stamina to read through the source. Jonathan

"Jonathan Turkanis" <technews@kangaroologic.com> writes:
"Pavel Vozenilek" <pavel_vozenilek@hotmail.com> wrote in message news:cgvjfh$arq$1@sea.gmane.org...
"Jonathan Turkanis" wrote:
I believe the attached file does what Pavel has in mind. Let someone
else
check it, though, since I'm not preprocessor expert.
The local iteration approach is bit simpler and would look like: ------------- #define BOOST_PP_LOCAL_MACRO( n ) \ template < BOOST_PP_ENUM_PARAMS(n, typename T) > \ explicit base_from_member( BOOST_PP_ENUM_BINARY_PARAMS(n, T, x) ) \ : member( BOOST_PP_ENUM_PARAMS(n, x) ) \ {} \ /**/
#define BOOST_PP_LOCAL_LIMITS (1, BOOST_BASE_FROM_MEMBER_MAX_ARITY) #include BOOST_PP_LOCAL_ITERATE() -------------
Thank's, Pavel. I find the preprocessor library fascinating but hard to learn since the basic techniques and terminology are not explained very well in the documentation
Have you looked at the new introduction which is linked through http://www.boost-consulting.com/boost/libs/preprocessor?
, and I don't have the stamina to read through the source.
Can't blame you. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote:
"Jonathan Turkanis" <technews@kangaroologic.com> writes:
"Pavel Vozenilek" <pavel_vozenilek@hotmail.com> wrote in message
The local iteration approach is bit simpler and would look like:
Thank's, Pavel. I find the preprocessor library fascinating but hard to
learn
since the basic techniques and terminology are not explained very well in
<snip> the
documentation
Have you looked at the new introduction which is linked through http://www.boost-consulting.com/boost/libs/preprocessor?
Excellent! I knew it was available but hadn't looked at it yet. I hope it -- or something similar -- will be incorporated into the PP docs. Jonathan

"Jonathan Turkanis" <technews@kangaroologic.com> writes:
"David Abrahams" <dave@boost-consulting.com> wrote:
"Jonathan Turkanis" <technews@kangaroologic.com> writes:
"Pavel Vozenilek" <pavel_vozenilek@hotmail.com> wrote in message
The local iteration approach is bit simpler and would look like:
<snip>
Thank's, Pavel. I find the preprocessor library fascinating but hard to
since the basic techniques and terminology are not explained very well in
learn the
documentation
Have you looked at the new introduction which is linked through http://www.boost-consulting.com/boost/libs/preprocessor?
Excellent! I knew it was available but hadn't looked at it yet. I hope it -- or something similar -- will be incorporated into the PP docs.
The link is incorporated. What more do you want to see? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote in message news:uekll5u8y.fsf@boost-consulting.com...
"Jonathan Turkanis" <technews@kangaroologic.com> writes:
"David Abrahams" <dave@boost-consulting.com> wrote:
Have you looked at the new introduction which is linked through http://www.boost-consulting.com/boost/libs/preprocessor?
Excellent! I knew it was available but hadn't looked at it yet. I hope it -- or something similar -- will be incorporated into the PP docs.
The link is incorporated. What more do you want to see?
Ideally, I'd like to see the contents of Appendix A reproduced, mutatis mutandis, as the Introduction to the Preprocessor Library. I realize this may not be possible; in that case, I'd like a similar overview incorporated directly into the docs. For example, I think it would be a bit odd if the introduction to Boost.Regex http://www.boost.org/libs/regex/doc/introduction.html just consisted of a link to an external article about regular expressions. I'm not criticizing the content at all. Jonathan

"Jonathan Turkanis" <technews@kangaroologic.com> writes:
"David Abrahams" <dave@boost-consulting.com> wrote in message news:uekll5u8y.fsf@boost-consulting.com...
"Jonathan Turkanis" <technews@kangaroologic.com> writes:
"David Abrahams" <dave@boost-consulting.com> wrote:
Have you looked at the new introduction which is linked through http://www.boost-consulting.com/boost/libs/preprocessor?
Excellent! I knew it was available but hadn't looked at it yet. I hope it -- or something similar -- will be incorporated into the PP docs.
The link is incorporated. What more do you want to see?
Ideally, I'd like to see the contents of Appendix A reproduced, mutatis mutandis, as the Introduction to the Preprocessor Library.
Why?
I realize this may not be possible; in that case, I'd like a similar overview incorporated directly into the docs.
It's probably possible, but I'm not sure it's a good idea. I'd have to keep yet another location up-to-date.
For example, I think it would be a bit odd if the introduction to Boost.Regex
http://www.boost.org/libs/regex/doc/introduction.html
just consisted of a link to an external article about regular expressions.
?? It's not analogous at all. The article isn't just about PP metaprogramming in general. It's a focused intro to the PP lib. Just what you'd want as an intro, no?
I'm not criticizing the content at all.
Jonathan
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote in message news:uekll4cp9.fsf@boost-consulting.com...
"Jonathan Turkanis" <technews@kangaroologic.com> writes:
"David Abrahams" <dave@boost-consulting.com> wrote in message news:uekll5u8y.fsf@boost-consulting.com...
"Jonathan Turkanis" <technews@kangaroologic.com> writes:
"David Abrahams" <dave@boost-consulting.com> wrote:
Have you looked at the new introduction which is linked through http://www.boost-consulting.com/boost/libs/preprocessor?
Excellent! I knew it was available but hadn't looked at it yet. I hope it -- or something similar -- will be incorporated into the PP docs.
The link is incorporated. What more do you want to see?
Ideally, I'd like to see the contents of Appendix A reproduced, mutatis mutandis, as the Introduction to the Preprocessor Library.
Why?
So the documentation is self-contained.
For example, I think it would be a bit odd if the introduction to Boost.Regex
http://www.boost.org/libs/regex/doc/introduction.html
just consisted of a link to an external article about regular expressions.
?? It's not analogous at all. The article isn't just about PP metaprogramming in general.
Fair enough. Let's say the it were a link to an article about Boost.Regex in CUJ. I would find it odd that the documentation was not better integrated. Getting back to PP, look at Topics --> Techniques. This section has some useful stuff, but really it should cover the topics in your appendix. Including both articles, with similar stated purposes, makes the documentation lack cohesion. Don't get me wrong -- it's far better with the link than without. I didn't mean to hit a raw nerve.
It's a focused intro to the PP lib. Just what you'd want as an intro, no?
Yes. Jonathan

On 8/27/04 11:48 PM, "Jonathan Turkanis" <technews@kangaroologic.com> wrote: [SNIP]
I've attached a version of base_from_member.hpp with configurable maximum arity, defaulting to 10. If you need higher arity, you #define BOOST_BASE_FROM_MEMBER_MAX_ARITY to an appropriate value before including the header.
The same technique will work for streambuf wrapping.
Thanks! -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

"Daryle Walker" wrote: _______________________________________________________________
2. docs: some introduction into the library would help.
This is a collection of many little libraries; I not sure that a grand introduction could be made.
Maybe something in form of table with features and their short description. _______________________________________________________________
3. docs: source code snippets should be syntax colorized
Even if that's a good idea, these are manually-created HTML files, so you have to wait until some automation is added.
Joaquín M López Muñoz had written very nice to use (Win32 based) tool to syntax colorize sources (based on Spirit). _______________________________________________________________
4.
#if (defined _MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif
should be put into each of headers. It has positive effect on VC ad Intel C++ compilation times.
I'm not using Visual C++, Windows, or even a IBM-style PC, so I don't want to go crazy with cross-platform conveniences that I can't check. I do want to know about cross-platform bugs, hopefully with fixes.
It is technique widely used in Boost and its positive effect has been reported. _______________________________________________________________
5. naming conventions: some names as
basic_constpointerbuf
are quite hard to read. Maybe they should
basic_const_pointer_buf
That standard stream (buffer) classes run their name-parts together.
IMHO it is big enough burden to decipher standard names. Having hard to read names in 3pp libraries makes maintenance frustrating.
(What happened to entry #6?)
I found it mistake and didn't bother to renumber. _______________________________________________________________
7. stream_buf_wrapping.hpp: there are three hardcoded constructors like:
template < typename T1, typename T2, typename T3 > basic_wrapping_ios( T1 x1, T2 x2, T3 x3 )
for 1, 2 and 3 parameters though base_from_member supports up to 10 parameters.
I wrote base_from_member, and I extended BFM after initially writing More-I/O.
Boost.Preprocessor can be used here to generate contructors of all available arities.
Any suggestions on how? And should I leave the arity number available in BFM (as a #define) so others can mirror it?
Jonathan answered. There are several ways to do it via Boost.PP, though. _______________________________________________________________
10. array_stream.hpp: the template
template < std::size_t N, typename Ch, class Tr > class basic_array_##SuffixF
may contain static assert N > 0.
A zero-size array will choke the compiler anyway.
It may be problem with GCC - this compiler may accept 0-length arrays. _______________________________________________________________
14. array_stream.hpp: the InputIterator in
template < typename InputIterator > basic_array_streambuf
can be 'concept-checked'.
How?
statis assert that (*InputIterator || InputIterator::value_type) is assignable to Ch.
And it is worth the extra code?
IMHO yes.
Like other templates, the current code will choke if the given type does not meet the expected interface (although with a nearly-incomprehensible error message).
That's the reason. _______________________________________________________________
15. iomanip_form.hpp: in
explicit basic_ios_form( ::std::basic_ios<Ch, Tr> const &i );
the parameters really should not be named 'i'.
Why not?
'i' is used as index for loops, this may confuse someone reading through code. _______________________________________________________________
17. iomanip_general.hpp: operator>>: I find the expression:
return s( is ), is;
abominable.
I don't think you have the right filename. Anyway, the code is hard to misinterpret and it saves a line.
I use the more_io4.zip. I once had to debug code containing such trick and would kill at that monent. _______________________________________________________________
20 iomanip.html: it should be explained what is "form-based".
The documentation should NOT be annotated code, it is very unreadable.
What do you mean by that? I've tried to imitate the Standard's way of describing items. Anyway, it's hard to be precise about the actions/effects without getting close to code when the functions are simple.
I mean documentation should not be only annotated code. I am looking for introduction and annotated examples. /Pavel

Download: http://groups.yahoo.com/group/boost/files/more_io_4.zip [or] http://boost-sandbox.sourceforge.net/more_io_4.zip
Are the docs available online anywhere?
* added generalizations to the new-line and skip-line manipulators
I won't get time to look at, let alone review, this and the other upcoming IO libraries, but I wondered if any of them (or perhaps even std components??) allow me to easily solve this problem: I'm using John Torjo's smart assert library (I hope he'll finish it off and submit to boost) which allow me to show object values when an assert happens, e.g.: SMART_ASSERT( this==that )(brd)(this)(that); 'brd' is an object representing a game board and it outputs the values in a 2d array. The operator<< does not output a leading carriage-return, but smart assert outputs something like this: brd = ' 1 2 3 4 5 6 7 8 9 a b c d e f g h i '; So, what I want is something to say insert a carriage-return before calling operator<<, e.g. SMART_ASSERT( this==that )(prefix_cr(brd))(this)(that); Or: SMART_ASSERT( this==that )("\n"<<brd)(this)(that); Darren
* added the non-oriented 'reset' and 'form' manipulators * split the manipulator header into several headers * changed the license statements
Your comments may be brief or lengthy, but basically the Review Manager needs your evaluation of the library. If you identify problems along the way, please note if they are minor, serious, or showstoppers.
Here are some questions you might want to answer in your review: What is your evaluation of the design? What is your evaluation of the implementation? What is your evaluation of the documentation? What is your evaluation of the potential usefulness of the library? Did you try to use the library? With what compiler? Did you have any problems? How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? Are you knowledgeable about the problem domain? And finally, every review should answer this question: Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall opinion.
For information about submitting a Formal Review, see http://www.boost.org/more/formal_review_process.htm
The Review manager is: Tom Brinkman reportbase@yahoo.com
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

"Darren Cook" <darren@dcook.org> wrote in message news:412AECFB.8060609@dcook.org...
Download: http://groups.yahoo.com/group/boost/files/more_io_4.zip [or] http://boost-sandbox.sourceforge.net/more_io_4.zip
Are the docs available online anywhere?
* added generalizations to the new-line and skip-line manipulators
I won't get time to look at, let alone review, this and the other upcoming IO libraries, but I wondered if any of them (or perhaps even std components??) allow me to easily solve this problem:
<snip>
'brd' is an object representing a game board and it outputs the values in a 2d array. The operator<< does not output a leading carriage-return, but smart assert outputs something like this:
brd = ' 1 2 3 4 5 6 7 8 9 a b c d e f g h i ';
So, what I want is something to say insert a carriage-return before calling operator<<, e.g. SMART_ASSERT( this==that )(prefix_cr(brd))(this)(that);
Why not something like: template<typename T> struct cr_prefixed { cr_prefixed(T& t) : t(t) { } void print(std::ostream& out) const { out << "\n" << t; } T& t; }; template<typename T> std::ostream& operator<<(std::ostream& out, const cr_prefixed<T>& p) { p.print(out); return out; } template<typename T> cr_prefixed<T> prefix_cr(T& t) { return cr_prefixed<T>(t); } Is there a more general version of the problem? Jonathan

So, what I want is something to say insert a carriage-return before calling operator<<, e.g. SMART_ASSERT( this==that )(prefix_cr(brd))(this)(that);
Why not something like: ...
Thanks! That worked.
Is there a more general version of the problem?
I don't know - I cannot remember needing to prefix anything other than a carriage-return. I need to indent a 2d output sometimes (e.g. in trace logs to show the depth of recursion) but that requires a prefix to each line so is a different kind of problem. Darren --------------------------------------- template<typename T> struct cr_prefixed { cr_prefixed(T& t) : t(t) { } void print(std::ostream& out) const { out << "\n" << t; } T& t; }; template<typename T> std::ostream& operator<<(std::ostream& out, const cr_prefixed<T>& p) { p.print(out); return out; } template<typename T> cr_prefixed<T> prefix_cr(T& t) { return cr_prefixed<T>(t); }

I need to indent a 2d output sometimes (e.g. in trace logs to show
"Darren Cook" <darren@dcook.org> wrote in message news:412BCACE.70300@dcook.org... the depth
of recursion) but that requires a prefix to each line so is a different kind of problem.
Larry Evans wrote a stream buffer to handle indentation. There appears to be a fairly recently modified version in the sandbox under boost/io/filters, but there is no documentation. If you like, I'll try to post an OutputFilter which manages indententation, but I'm not sure what your requirements are. What interface would you like? Jonathan

On 8/24/04 3:23 AM, "Darren Cook" <darren@dcook.org> wrote:
Download: http://groups.yahoo.com/group/boost/files/more_io_4.zip [or] http://boost-sandbox.sourceforge.net/more_io_4.zip
Are the docs available online anywhere? [TRUNCATE unrelated request]
Not directly. The docs are in the archive. The More-I/O library is developing in the Boost Sandbox, so you can look at its files (code and docs) through CVS (for which SourceForge has special web-page viewing support). -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

Here's my review. Let me state first that I have a certain bias, because I have submitted an iostreams library (http://tinyurl.com/3m6ur) which overlaps with the current library somewhat. It consists of a general framework for constructing streams and stream buffers; all of the stream buffers included in the currently library can be defined with just a few lines of code using my library, and I believe that is the better approach. ---------------------------------------- Summary: <boost/io/streambuf_wrapping.hpp>: Reject, because it reduces the work required to produce a stream from a stream buffer only marginally, if at all. <boost/io/array_stream.hpp>: Reject, as insufficiently motivated. <boost/io/pointer_stream.hpp>: Accept (with qualification). <boost/io/null_stream.hpp>: Accept (with qualification). <boost/io/value_stream.hpp>: Reject, as insufficiently motivated. <boost/io/iomanip.hpp>: Accept resetios, skipl and multi_skipl and reject the others. ---------------------------------------- Basic Review Questions: - What is your evaluation of the design? The library seems to be a collection of bits and pieces. This is not bad in itself, but I'd rather see a more systematic treatment. - What is your evaluation of the implementation? I checked the implementation only in a few places, because I couldn't understand the documentation. Most of what I saw was okay, but there are several problems pointed out below. - What is your evaluation of the documentation? The documentation is poor. It seems to consist only of 'reference documentation'. It needs an overview, examples and perhaps a tutorial. The descriptions and the rationales are generally insufficient (more below). - What is your evaluation of the potential usefulness of the library? All the components I voted to accept are moderately useful. I don't think any fills a burning need. - Did you try to use the library? With what compiler? Did you have any problems? I tried to use array_stream and found it wouldn't compile one VC7.1 and como 4.3.3, as I reported. - How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? I spent about two hours looking at the documentation and sources and writing this review. I also read many of the reviews from last time around. - Are you knowledgeable about the problem domain? I am very knowledgable about stream buffers but have only a basic knowledge of manipulators. - Do you think the library should be accepted as a Boost library? See summary. ---------------------------------------- <boost/io/streambuf_wrapping.hpp>: I vote to reject, for the following reasons. I don't accept the criticism that the proper way to use a custom streambuf is with a plain istream, ostream or iostream; it's nice to have matching stream classes to go with a custom stream buffer class. However, if one has written a custom stream buffer, the name basic_wrapping_xstream is not what most people want for the matching streams. If the streambuf is called mapped_filebuf, a matching i/o stream might be named mapped_fstream. This could be solved with template aliases: template<typename Ch> using mapped_fstream = basic_wrapping_iostream< mapped_filebuf<Ch> >; Using streambuf_wrapping.hpp and the current language, the way to achieve this is to derive a stream class from basic_wrapping_iostream< mapped_filebuf<...> >: template<typename Ch> class mapped_fstream : basic_wrapping_iostream<mapped_filebuf> { ... }; The problem with this is that one has to write new constructors, since they are not inherited. If one wants to follow the example of the standard library file and string streams, one should also repeat the typedefs char_type, traits_type, pos_type, etc. As a result, the above is scarcely easier than writing mapped_fstream from scratch, since writing the constructors (and typedefs) is the principle difficulty. Without template aliases, a macro-based approach would be more useful: #define BOOST_IO_DEFINE_WRAPPING_ISTREAM(stream, streambuf, arity) #define BOOST_IO_DEFINE_WRAPPING_OSTREAM(stream, streambuf, arity) #define BOOST_IO_DEFINE_WRAPPING_IOSTREAM(stream, streambuf, arity) BOOST_IO_DEFINE_WRAPPING_ISTREAM(mapped_fstream, mapped_filebuf, 1) Also, let me note that with my library, streams and stream buffers are generated simultaneously using stream_facade and streambuf_facade, so you will rarely need to write a stream buffer from scratch and wrap it in a stream. E.g. struct tcp_resource { ... }; typedef streambuf_facade<tcp_resource> tcp_streambuf; typedef stream_facade<tcp_resource> tcp_stream; ---------------------------------------- <boost/io/array_stream.hpp>: I vote to reject, for the following reasons. 1. std::stringstream already writes to an internally managed character array, but it suffers from the following limitations (both resaonable in context) a. You can't define a stringstream to access a region of memory specified in advance b. when you finish performing i/o, you can't get direct access to the underlying array. array_stream addresses b but not a, and doesn't address b very well, since the lifetime of the array is included in the lifetime of the stream. I believe the pointer streams are better in every respect than the array streams. 2. basic_array_streambuf should be implemented as a thin wrapper around basic_pointerbuf. Otherwise, you've got unnecessary code bloat, since all the code is duplicated for each value of N. ---------------------------------------- <boost/io/pointer_stream.hpp>: I think pointer streams and stream buffers are moderately useful, and would vote for acceptance, but I have the following objections. 1. Having separate classes for const and non-const pointers leads to far too many templates. Const-correctness can be enforced by the stream buffer by not allowing constructors taking const char* to set the put area. 2. The interface is strange and poorly documented. For example, the specification of begin_pointer and end_pointer refer to the 'utilized array-segment'. What does this mean? Looking at the source, I see that they return pointer delimiting the get area, if the get area is valid, and pointers delimiting the put area otherwise. Why not simply make them return the pointers passed to the constructor, and call them begin and end? Together with the current seek positions -- available using pubseekoff -- this should give the user all the necessary information in a less confusing way. Here's how I handle the situation in my library. There are three light-weight templates basic_array_source, basic_array_sink and basic_array_resource, for accessing arrays in read-only, write only and read-write mode. There are also typedefs array_source, array_sink, ... . You can now defined array streams as follows: typedef stream_facade<array_source> array_istream; typedef stream_facade<array_sink> array_ostream; typedef stream_facade<array_resource> array_iostream; These streams have a simple open/is_open/close interface like std::fstream: char buf1[1000]; char buf2[10000]; // Write to buf1: stream_facade<array_sink> out(buf, buf + 10000); out << "hello first array!" << std::ends; out.close(); // Write to buf2: out.open(buf2, buf2 + 10000); out << "hello second array!" << std::ends; out.close(); // Read from an array: const char* str = "hello array!\n"; streambuf_facade<array_source> in(str, str + std::strlen(str)); std::cout << ∈ // Writes "hello array!" ---------------------------------------- <boost/io/null_stream.hpp>: I don't understand the stated rationale for this stream. Are you saying someone might want to use it to implement a command-line interface? An alternative rationale would be this: sometimes a C++ interface requires that the user pass an ostream to receive output, but the user doesn't care about the output. I have seen a request for a stream like this on comp.lang.c++, and I think it would be a moderately useful component. Using my library it can be implemented as follows (as a narrow-character sink, for simplicity): struct null_sink : sink { void write(const char*, std::streamsize) { } }; typedef stream_facade< null_sink<char> > null_ostream; etc. This actually allows a null stream to be buffered, which improves efficiency even if you're going to throw the output away. ---------------------------------------- <boost/io/value_stream.hpp>: As above, the rationale doesn't make sense. Unlike above, however, I can't think of a reasonable alternative rationale. BTW, it can be implemented like this using my library (as a narrow-character source, for simplicity): struct value_source : source { char val; value_source(char val) : val(val) { } std::streamsize read(char* s, std::streamsize n) { std::memset(s, (unsigned char) val, n); return n; } }; typedef stream_facade<value_source> value_stream; value_stream in('a'); char c; in >> c; assert(c == 'a'); ------------------------------------------ <boost/io/iomanip.hpp> - basic_ios_form: I don't understand what this template is supposed to do. You need a better description and some examples. Otherwise, I vote to reject. - resetios: I believe this would be useful. - skipl, multi_skipl: These sound useful too, though I agree with Pavel that the names are too cryptic. - multi_skipper: I'm not sure I see why this is needed; how often do you need to skip a sequence of repeated characters? Id rather see a utility that skips a certain specified sequence of characters, and sets failbit otherwise, as described by Dietmar Kuehl here: http://tinyurl.com/3jzwg - multi_newer: How often do you need to write multiple copies of a character to a stream? And isn't it easy to do so already? The name is bad, too. I vote to reject. - multi_newl: Same as multi_newer. I don't see the need for inserting long sequences of newline characters. - newl: This is a good idea. But I think this may be one of the rare components which I would like to see added to the standard library but not to boost. If it were part of the standard, every C++ programmer would be expected to know what it means. But I can't see myself including a boost header just to avoid writing "\n": most people won't know what newl it means, so rather than being self-documenting using it would be self-obfuscating. I vote to reject. Best Regards, Jonathan

From: "Jonathan Turkanis" <technews@kangaroologic.com>
<boost/io/null_stream.hpp>:
I don't understand the stated rationale for this stream. Are you saying someone might want to use it to implement a command-line interface?
It may not be worded extremely well, but it certainly doesn't say that. (Something I noticed reading the rationale is the incorrect "an user." That should be "a user" since "user" doesn't start with a vowel sound. (Isn't English grand?)
An alternative rationale would be this: sometimes a C++ interface requires that the user pass an ostream to receive output, but the user doesn't care about the output. I have seen a request for a stream like this on comp.lang.c++, and I think it would be a moderately useful
It is a useful idea. I'd word the rationale more like this: "There are occasions in which one needs to provide an input or output stream(buf) to a function, but when there should be no input or all output should be ignored. In such situations, a null stream(buf), the IOStreams equivalent of *nix's /dev/null and Windows/DOS' NUL:, is needed."
component. Using my library it can be implemented as follows (as a narrow-character sink, for simplicity):
struct null_sink : sink { void write(const char*, std::streamsize) { } }; typedef stream_facade< null_sink<char> > null_ostream; etc.
This actually allows a null stream to be buffered, which improves efficiency even if you're going to throw the output away.
That's an important distinction, over and above any simplicity of definition. You should provide a null sink, source, istream, and ostream in your submission.
----------------------------------------
<boost/io/value_stream.hpp>:
As above, the rationale doesn't make sense. Unlike above, however, I can't think of a reasonable alternative rationale. BTW, it can be
"On occasion, you may need to provide an input stream(buf) to a function that only ever returns a particular character, and never runs out of that character. This is analogous to special files in *nix such as /dev/zero, which returns as many zeroes as you care to read from it. In those situations, you need value stream(buf)s."
------------------------------------------
<boost/io/iomanip.hpp>
- basic_ios_form: I don't understand what this template is supposed to do. You need a better description and some examples. Otherwise, I vote to reject.
It wasn't clear to me either, but I think I understand it to provide a means to capture a set of manipulations one wants applied to a stream so that the entire set can be applied at once. An interesting design aspect, which I only noticed upon writing this, is that the mfs fill(), precision(), width(), etc., all return a reference to the instance. That means that one can create a temporary, unnamed instance and then chain calls to those mfs to set all of the attributes desired. This is more compact and readable than using std::setfill, std::setprecision, std::setw, etc.: std::cout << std::setfill(' ') << std::setprecision(3) << std::setw(10) << ... std::cout << boost::io::basic_ios_form() .fill(' ') .precision(3) .width(10) << ... That really lends itself to writing readably. You can also assume that a using directive is in effect, yielding: cout << setfill(' ') << setprecision(3) << setw(10) << ... cout << basic_ios_form().fill(' ').precision(3).width(10) << ... That tips the scale in favor of the std manipulators. Beyond the use of namespaces, the remaining question is whether using boost::io::basic_ios_form is superior to: std::cout.fill(' '); std::cout.precision(3); std::cout.width(10); std::cout << ... After all of that, you might question the utility of boost::io::basic_ios_form, but don't forget that you can create an instance and then reuse it. Consequently, with a better name, I think it is useful.
- skipl, multi_skipl: These sound useful too, though I agree with Pavel that the names are too cryptic.
std::endl is the precendent. I don't think skipl is too cryptic. Making it less so means making it longer and that reduces its value as a manipulator. (Too cryptic outweights a short name, but I don't think this fits the "too cryptic" category.)
- multi_skipper: I'm not sure I see why this is needed; how often do you need to skip a sequence of repeated characters? Id rather
When parsing, it is often useful to ensure that there were exactly 10 spaces between one token and the next, for example.
see a utility that skips a certain specified sequence of characters, and sets failbit otherwise, as described by Dietmar Kuehl here: http://tinyurl.com/3jzwg
I agree that the generalized version that permits skipping an arbitrary string is likewise useful, but to duplicate multi_skipper's functionality, you'd have to create a string with the desired number of a character and then skip that. When you want to skip a certain number of one character, multi_skipper is better. The generalized class could, of course, provide both capabilities rather trivially.
- multi_newer: How often do you need to write multiple copies of a character to a stream? And isn't it easy to do so already? The name is bad, too. I vote to reject.
I'm sure one doesn't need to write multiple copies of a character to a stream too often, but why reject this manipulator on the grounds that it isn't needed very often? A generalized version that takes a string would be useful, too.
- multi_newl: Same as multi_newer. I don't see the need for inserting long sequences of newline characters.
There are occasions in which one wants to insert multiple newlines. As a complement to newl, I don't see a problem with keeping multi_newl.
- newl: This is a good idea. But I think this may be one of the rare components which I would like to see added to the standard library but not to boost. If it were part of the standard, every C++ programmer would be expected to know what it means. But I can't see myself including a boost header just to avoid writing "\n": most people won't know what newl it means, so rather than being self-documenting using it would be self-obfuscating. I vote to reject.
That seems a particularly bad approach. It won't get into the Standard for quite some time and, in the meantime, users can use it and prove its soundness and value. As it happens, inserting "\n" is slower than using newl because of the formatted I/O logic of streams and because of the invocation of (in effect, at least) strlen(). -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

"Rob Stewart" <stewart@sig.com> wrote in message news:200408262114.i7QLEOP14442@lawrencewelk.systems.susq.com...
From: "Jonathan Turkanis" <technews@kangaroologic.com>
<boost/io/null_stream.hpp>:
I don't understand the stated rationale for this stream. Are you saying someone might want to use it to implement a command-line interface?
It may not be worded extremely well, but it certainly doesn't say that.
I know it doesn't say that ... I was trying to fill in the blanks.
An alternative rationale would be this: sometimes a C++ interface requires that the user pass an ostream to receive output, but the user doesn't care about the output. I have seen a request for a stream like this on comp.lang.c++, and I think it would be a moderately useful
That's an important distinction, over and above any simplicity of definition. You should provide a null sink, source, istream, and ostream in your submission.
My feeling is that once you have the null sink (or source), you don't need to include the streams in the library, since its so easy to write typedef stream_facade<null_sink> null_ostream;
- basic_ios_form: I don't understand what this template is supposed to do. You need a better description and some examples. Otherwise, I vote to reject.
It wasn't clear to me either, but I think I understand it to provide a means to capture a set of manipulations one wants applied to a stream so that the entire set can be applied at once.
I see. That does sound useful. My vote to reject is really a challenge to Daryle -- I don't feel I should have to wade through the reference documentation or the source to figure out what a component is supposed to do.
That really lends itself to writing readably. You can also assume that a using directive is in effect, yielding:
cout << setfill(' ') << setprecision(3) << setw(10) << ...
cout << basic_ios_form().fill(' ').precision(3).width(10) << ...
That tips the scale in favor of the std manipulators.
Also, the former can easily be broken over several lines: cout << setfill(' ') << setprecision(3) << setw(10) << ... But it's a matter of taste.
- skipl, multi_skipl: These sound useful too, though I agree with Pavel that the names are too cryptic.
std::endl is the precendent. I don't think skipl is too cryptic. Making it less so means making it longer and that reduces its value as a manipulator. (Too cryptic outweights a short name, but I don't think this fits the "too cryptic" category.)
Why are skipl and multi_skipl better than skip_line and skip_lines?
- multi_skipper: I'm not sure I see why this is needed; how often do you need to skip a sequence of repeated characters? Id rather
When parsing, it is often useful to ensure that there were exactly 10 spaces between one token and the next, for example.
I'll take your word for it, but an example would help. I am used to just worrying about whitespace.
see a utility that skips a certain specified sequence of characters, and sets failbit otherwise, as described by Dietmar Kuehl here: http://tinyurl.com/3jzwg
I agree that the generalized version that permits skipping an arbitrary string is likewise useful, but to duplicate multi_skipper's functionality, you'd have to create a string with the desired number of a character and then skip that.
I agree that the component I suggested would be a poor substitute for the original component, if the latter is in fact useful.
- multi_newer: How often do you need to write multiple copies of a character to a stream? And isn't it easy to do so already? The name is bad, too. I vote to reject.
I'm sure one doesn't need to write multiple copies of a character to a stream too often, but why reject this manipulator on the grounds that it isn't needed very often?
Because it clutters up the library, making it harder for people to find the parts they really need. Also, the straightforward way of writing a sequence of repeated characters to a stream makes it immediately obvious what is being done, whereas programmers looking at code written by someone else can't be expected to know what multi_newer does. If a component fills an important need, it's reasonable to expect people to learn about it if they want to understand your code -- otherwise, I don't see the point.
There are occasions in which one wants to insert multiple newlines. As a complement to newl, I don't see a problem with keeping multi_newl.
If both are accepted, I'd like them to be called new_line and new_lines (or newline and newlines).
- newl: This is a good idea. But I think this may be one of the rare components which I would like to see added to the standard library but not to boost. If it were part of the standard, every C++ programmer would be expected to know what it means. But I can't see myself including a boost header just to avoid writing "\n": most people won't know what newl it means, so rather than being self-documenting using it would be self-obfuscating. I vote to reject.
That seems a particularly bad approach.
In general, yes.
It won't get into the Standard for quite some time and, in the meantime, users can use it and prove its soundness and value.
The main benefit of newl (I think) is that it calls attention to a character which receives special treatment in some contexts. It can't achieve this purpose unless people know what it means. I wouldn't want someone examining my code to spend time looking through boost documentation only to find that the manipulator just writes a newline.
As it happens, inserting "\n" is slower than using newl because of the formatted I/O logic of streams and because of the invocation of (in effect, at least) strlen().
My guess is that in typical cases this difference is miniscule. If this is an important part of the rationale, I'd like to see some performance data. Best Regards, Jonathan

From: "Jonathan Turkanis" <technews@kangaroologic.com>
"Rob Stewart" <stewart@sig.com> wrote in message news:200408262114.i7QLEOP14442@lawrencewelk.systems.susq.com...
From: "Jonathan Turkanis" <technews@kangaroologic.com>
That's an important distinction, over and above any simplicity of definition. You should provide a null sink, source, istream, and ostream in your submission.
My feeling is that once you have the null sink (or source), you don't need to include the streams in the library, since its so easy to write
typedef stream_facade<null_sink> null_ostream;
Sure, but then every developer that wants one must write the same typedef. Why not standardize the name by providing it with the library?
std::endl is the precendent. I don't think skipl is too cryptic. Making it less so means making it longer and that reduces its value as a manipulator. (Too cryptic outweights a short name, but I don't think this fits the "too cryptic" category.)
Why are skipl and multi_skipl better than skip_line and skip_lines?
"skipl" is shorter than "skip_line" and I figured it would be used more frequently as a result. However, I really like "skip_lines" (as opposed to "multi_skipl") and extraction operations that need to skip lines are not terribly common, so the added length of "skip_line" and its symmetry with "skip_lines" makes it a win.
- multi_skipper: I'm not sure I see why this is needed; how often do you need to skip a sequence of repeated characters? Id rather
When parsing, it is often useful to ensure that there were exactly 10 spaces between one token and the next, for example.
I'll take your word for it, but an example would help. I am used to just worrying about whitespace.
Reece provided some useful examples. I hope they're sufficient. If not, I guess I could come up with some given a few minutes time. However, in keeping with the "skip_line" idea, perhaps this would be better named "skip_char?"
see a utility that skips a certain specified sequence of characters, and sets failbit otherwise, as described by Dietmar Kuehl here: http://tinyurl.com/3jzwg
I agree that the generalized version that permits skipping an arbitrary string is likewise useful, but to duplicate multi_skipper's functionality, you'd have to create a string with the desired number of a character and then skip that.
I agree that the component I suggested would be a poor substitute for the original component, if the latter is in fact useful.
It could be named "skip_string."
- multi_newer: How often do you need to write multiple copies of a character to a stream? And isn't it easy to do so already? The name is bad, too. I vote to reject.
I'm sure one doesn't need to write multiple copies of a character to a stream too often, but why reject this manipulator on the grounds that it isn't needed very often?
Because it clutters up the library, making it harder for people to find the parts they really need.
Also, the straightforward way of writing a sequence of repeated characters to a stream makes it immediately obvious what is being done, whereas programmers looking at code written by someone else can't be expected to know what multi_newer does. If a component fills an important need, it's reasonable to expect people to learn about it if they want to understand your code -- otherwise, I don't see the point.
Daryle can build his own defense on why he included multi_newer. It is cleaner than inserting the same character multiple times. You're right that it's not an improvement over inserting std::string('c', n). The name, of course, is a problem, too.
There are occasions in which one wants to insert multiple newlines. As a complement to newl, I don't see a problem with keeping multi_newl.
If both are accepted, I'd like them to be called new_line and new_lines (or newline and newlines).
As I said, I think "newl" is fine, as compared to "endl," but "multi_newl" is less satisfying than "newlines." (I prefer "newline" to "new_line.") I use an "nl" manipulator, so mine is even more cryptic than "newl," but I think it is fine. ("nls" doesn't work too well, though, as a name for the multiple nl version.) I suppose the question is whether multi_newer('\n'), with whatever name it might use, would be the better way to spell "multi_newl."
It won't get into the Standard for quite some time and, in the meantime, users can use it and prove its soundness and value.
The main benefit of newl (I think) is that it calls attention to a character which receives special treatment in some contexts. It can't achieve this purpose unless people know what it means. I wouldn't want someone examining my code to spend time looking through boost documentation only to find that the manipulator just writes a newline.
I don't think many would have a hard time recognizing the parallel between "newl" and "endl." If you rename it to "newline," there's no chance of misunderstanding the manipulator, right?
As it happens, inserting "\n" is slower than using newl because of the formatted I/O logic of streams and because of the invocation of (in effect, at least) strlen().
My guess is that in typical cases this difference is miniscule. If this is an important part of the rationale, I'd like to see some performance data.
I use preincrement/predecrement unless I need the post* version so that my code is certain to be optimal. I create an end iterator outside of any loops that I may write so that the end() mf isn't evaluated each time through the loop. There are many things that I do out of habit that ensure that I'm writing the most efficient code I can before I profile to find algorithmic hotspots to address. I see the use of a newline manipulator as another such tool that ensures that inserting a newline isn't something someone would have to revisit when looking to improve performance. IOW, the penalty for inserting '\n' or "\n" may not matter, but with a newline manipulator, I can expect it won't ever be the problem. (If it is, then its only one of many operations that are a problem and I'd need to use a different I/O scheme altogether.) -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

"Rob Stewart" <stewart@sig.com> wrote in message:
From: "Jonathan Turkanis" <technews@kangaroologic.com>
"Rob Stewart" <stewart@sig.com> wrote in message news:200408262114.i7QLEOP14442@lawrencewelk.systems.susq.com...
From: "Jonathan Turkanis" <technews@kangaroologic.com>
That's an important distinction, over and above any simplicity of definition. You should provide a null sink, source, istream, and ostream in your submission.
My feeling is that once you have the null sink (or source), you don't need to include the streams in the library, since its so easy to write
typedef stream_facade<null_sink> null_ostream;
Sure, but then every developer that wants one must write the same typedef. Why not standardize the name by providing it with the library?
I'm torn. I'm trying to keep the number of library-defined types to an absolute minimum, since I've already had a complaint that there are too many names to remember.
std::endl is the precendent. I don't think skipl is too cryptic. Making it less so means making it longer and that reduces its value as a manipulator. (Too cryptic outweights a short name, but I don't think this fits the "too cryptic" category.)
Why are skipl and multi_skipl better than skip_line and skip_lines?
"skipl" is shorter than "skip_line" and I figured it would be used more frequently as a result. However, I really like "skip_lines" (as opposed to "multi_skipl") and extraction operations that need to skip lines are not terribly common, so the added length of "skip_line" and its symmetry with "skip_lines" makes it a win.
Yes, I think skip_line/skip_lines is a good combination.
- multi_skipper: I'm not sure I see why this is needed; how often do you need to skip a sequence of repeated characters? Id rather
When parsing, it is often useful to ensure that there were exactly 10 spaces between one token and the next, for example.
I'll take your word for it, but an example would help. I am used to just worrying about whitespace.
Reece provided some useful examples. I hope they're sufficient.
Yes. I found the padding example more convincing than the Haskel example, because of the extra functionality needed in the latter case.
If not, I guess I could come up with some given a few minutes time. However, in keeping with the "skip_line" idea, perhaps this would be better named "skip_char?"
I like plain old 'skip', which should be able to double duty as multi_skipper and skip_string: cin >> skip('c', 10) cin >> skip("hello world") In another post I also suggest skip_if and skip_to.
There are occasions in which one wants to insert multiple newlines. As a complement to newl, I don't see a problem with keeping multi_newl.
If both are accepted, I'd like them to be called new_line and new_lines (or newline and newlines).
As I said, I think "newl" is fine, as compared to "endl," but "multi_newl" is less satisfying than "newlines." (I prefer "newline" to "new_line.")
The main benefit of newl (I think) is that it calls attention to a character which receives special treatment in some contexts. It can't achieve this
I like newline and newlines. purpose
unless people know what it means. I wouldn't want someone examining my code to spend time looking through boost documentation only to find that the manipulator just writes a newline.
I don't think many would have a hard time recognizing the parallel between "newl" and "endl." If you rename it to "newline," there's no chance of misunderstanding the manipulator, right?
Yes. I was too hasty in rejecting it. Even if it's called "newline", though, people may still wonder why it's being used instead of endl or "\n" and end up consulting the documentation.
As it happens, inserting "\n" is slower than using newl because of the formatted I/O logic of streams and because of the invocation of (in effect, at least) strlen().
My guess is that in typical cases this difference is miniscule. If this is an important part of the rationale, I'd like to see some performance data.
I use preincrement/predecrement unless I need the post* version so that my code is certain to be optimal. I create an end iterator outside of any loops that I may write so that the end() mf isn't evaluated each time through the loop. There are many things that I do out of habit that ensure that I'm writing the most efficient code I can before I profile to find algorithmic hotspots to address.
I do this stuff, too. The situation is different with library components, though. Imagine someone proposing a new container based on its performance characteristics but not presenting any performance data. At any rate, you and Reece have convinced me that my rejection of some of the manipulators was rash. I'm still not sure about ios_form; I'd like to hear Daryle's rationale. BTW -- Daryle, where are you??? I'd like to hear your answers to some of my objections. Best Regards, Jonathan

On 8/27/04 6:43 PM, "Jonathan Turkanis" <technews@kangaroologic.com> wrote:
"Rob Stewart" <stewart@sig.com> wrote in message:
From: "Jonathan Turkanis" <technews@kangaroologic.com>
"Rob Stewart" <stewart@sig.com> wrote in message news:200408262114.i7QLEOP14442@lawrencewelk.systems.susq.com... [SNIP] The main benefit of newl (I think) is that it calls attention to a character which receives special treatment in some contexts. It can't achieve this purpose unless people know what it means. I wouldn't want someone examining my code to spend time looking through boost documentation only to find that the manipulator just writes a newline.
I don't think many would have a hard time recognizing the parallel between "newl" and "endl." If you rename it to "newline," there's no chance of misunderstanding the manipulator, right?
I know "new_line" or "newline" would be clearer, but "newl" happens to be the same length as typing in ['\n'] or ["\n"], four characters. If I change "skipl" to "skip_line", I should do the same to "newl" to be consistent.
Yes. I was too hasty in rejecting it. Even if it's called "newline", though, people may still wonder why it's being used instead of endl or "\n" and end up consulting the documentation.
As it happens, inserting "\n" is slower than using newl because of the formatted I/O logic of streams and because of the invocation of (in effect, at least) strlen().
My guess is that in typical cases this difference is miniscule. If this is an important part of the rationale, I'd like to see some performance data.
I use preincrement/predecrement unless I need the post* version so that my code is certain to be optimal. I create an end iterator outside of any loops that I may write so that the end() mf isn't evaluated each time through the loop. There are many things that I do out of habit that ensure that I'm writing the most efficient code I can before I profile to find algorithmic hotspots to address.
I do this stuff, too. The situation is different with library components, though. Imagine someone proposing a new container based on its performance characteristics but not presenting any performance data.
I think someone (Paul?) did a performance test during last year's review. I don't recall how it turned out.
At any rate, you and Reece have convinced me that my rejection of some of the manipulators was rash. I'm still not sure about ios_form; I'd like to hear Daryle's rationale.
I've read Stroustrup's C++ book (third edition) a lot. A lot of submission ideas come from examples in his book. The form class was one of them. I realized that packaging a set of formatting changes for later and/or repeated use could be helpful (e.g. tables).
BTW -- Daryle, where are you??? I'd like to hear your answers to some of my objections.
-- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

"Daryle Walker" <darylew@hotmail.com> wrote in message:
On 8/27/04 6:43 PM, "Jonathan Turkanis" <technews@kangaroologic.com> wrote:
"Rob Stewart" <stewart@sig.com> wrote in message:
I don't think many would have a hard time recognizing the parallel between "newl" and "endl." If you rename it to "newline," there's no chance of misunderstanding the manipulator, right?
I know "new_line" or "newline" would be clearer, but "newl" happens to be the same length as typing in ['\n'] or ["\n"], four characters. If I change "skipl" to "skip_line", I should do the same to "newl" to be consistent.
Repeating myself a bit, I like nelwine/newlines, skip_line/skip_lines.
I think someone (Paul?) did a performance test during last year's review. I don't recall how it turned out.
At any rate, you and Reece have convinced me that my rejection of some of
I'd like to see it. I remember some on comp.lang.c++ claimed to have done some performance tests on this or a related issue, but it turned out he was using test files consisting entirely of newlines. ;-) the
manipulators was rash. I'm still not sure about ios_form; I'd like to hear Daryle's rationale.
I've read Stroustrup's C++ book (third edition) a lot. A lot of submission ideas come from examples in his book. The form class was one of them. I realized that packaging a set of formatting changes for later and/or repeated use could be helpful (e.g. tables).
Defintely explain this in the docs. Jonathan

From: Daryle Walker <darylew@hotmail.com>
On 8/27/04 6:43 PM, "Jonathan Turkanis" <technews@kangaroologic.com> wrote:
"Rob Stewart" <stewart@sig.com> wrote in message:
I don't think many would have a hard time recognizing the parallel between "newl" and "endl." If you rename it to "newline," there's no chance of misunderstanding the manipulator, right?
I know "new_line" or "newline" would be clearer, but "newl" happens to be the same length as typing in ['\n'] or ["\n"], four characters. If I change "skipl" to "skip_line", I should do the same to "newl" to be consistent.
"newline" is easier to type than "\n" or '\n' so the comparative length isn't really an issue. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

"Jonathan Turkanis" wrote:
Yes, I think skip_line/skip_lines is a good combination.
I like newline and newlines.
It is often recomended not to distinguish names only on plural suffix. Easy to overlook bug here. /Pavel

"Pavel Vozenilek" <pavel_vozenilek@hotmail.com> wrote in message news:cgpgmb$gla$1@sea.gmane.org...
"Jonathan Turkanis" wrote:
Yes, I think skip_line/skip_lines is a good combination.
I like newline and newlines.
It is often recomended not to distinguish names only on plural suffix. Easy to overlook bug here.
I know that's a consideration. But then there's tuple and tuples... Jonathan

On 8/27/04 12:42 PM, "Rob Stewart" <stewart@sig.com> wrote:
From: "Jonathan Turkanis" <technews@kangaroologic.com>
"Rob Stewart" <stewart@sig.com> wrote in message news:200408262114.i7QLEOP14442@lawrencewelk.systems.susq.com...
From: "Jonathan Turkanis" <technews@kangaroologic.com> [SNIP]
- multi_newer: How often do you need to write multiple copies of a character to a stream? And isn't it easy to do so already? The name is bad, too. I vote to reject.
I'm sure one doesn't need to write multiple copies of a character to a stream too often, but why reject this manipulator on the grounds that it isn't needed very often?
Because it clutters up the library, making it harder for people to find the parts they really need.
Also, the straightforward way of writing a sequence of repeated characters to a stream makes it immediately obvious what is being done, whereas programmers looking at code written by someone else can't be expected to know what multi_newer does. If a component fills an important need, it's reasonable to expect people to learn about it if they want to understand your code -- otherwise, I don't see the point.
Daryle can build his own defense on why he included multi_newer. It is cleaner than inserting the same character multiple times. You're right that it's not an improvement over inserting std::string('c', n). The name, of course, is a problem, too. [TRUNCATE]
The idea for "multi_newer" just popped into my head. The string solution is worse because it forces an extra memory allocation. -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

"Daryle Walker" <darylew@hotmail.com> wrote in message:
Daryle can build his own defense on why he included multi_newer. It is cleaner than inserting the same character multiple times. You're right that it's not an improvement over inserting std::string('c', n). The name, of course, is a problem, too. [TRUNCATE]
The idea for "multi_newer" just popped into my head. The string solution is worse because it forces an extra memory allocation.
I wouldn't use a string in place of a fixed number of repeitions of a given character. I said this in some other message, but I like cout << repeat('c', 17) Jonathan

"Jonathan Turkanis" wrote:
I wouldn't use a string in place of a fixed number of repeitions of a given character. I said this in some other message, but I like
cout << repeat('c', 17)
'repeat' term is used by function in Assign library (I think I suggested its name). Possible collisions should be checked. /Pavel

"Pavel Vozenilek" <pavel_vozenilek@hotmail.com> wrote in message news:cgs7dt$c50$1@sea.gmane.org...
"Jonathan Turkanis" wrote:
I wouldn't use a string in place of a fixed number of repeitions of a given character. I said this in some other message, but I like
cout << repeat('c', 17)
'repeat' term is used by function in Assign library (I think I suggested its name).
Possible collisions should be checked.
The manipulators are in namespace boost::io, which I think will be sufficient to prevent collisions. Jonathan

From: Daryle Walker <darylew@hotmail.com>
On 8/27/04 12:42 PM, "Rob Stewart" <stewart@sig.com> wrote:
From: "Jonathan Turkanis" <technews@kangaroologic.com>
"Rob Stewart" <stewart@sig.com> wrote in message news:200408262114.i7QLEOP14442@lawrencewelk.systems.susq.com...
From: "Jonathan Turkanis" <technews@kangaroologic.com> [SNIP]
- multi_newer: How often do you need to write multiple copies of a character to a stream? And isn't it easy to do so already? The name is bad, too. I vote to reject.
I'm sure one doesn't need to write multiple copies of a character to a stream too often, but why reject this manipulator on the grounds that it isn't needed very often?
Because it clutters up the library, making it harder for people to find the parts they really need.
Also, the straightforward way of writing a sequence of repeated characters to a stream makes it immediately obvious what is being done, whereas programmers looking at code written by someone else can't be expected to know what multi_newer does. If a component fills an important need, it's reasonable to expect people to learn about it if they want to understand your code -- otherwise, I don't see the point.
Daryle can build his own defense on why he included multi_newer. It is cleaner than inserting the same character multiple times. You're right that it's not an improvement over inserting std::string('c', n). The name, of course, is a problem, too.
The idea for "multi_newer" just popped into my head. The string solution is worse because it forces an extra memory allocation.
I bring you back to the question at the top: how often does one need to do this? I contend it isn't often and the memory allocation for building the string is most likely swamped by the other overhead in writing it and whatever accompanies it on the output device. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

On 8/26/04 1:38 AM, "Jonathan Turkanis" <technews@kangaroologic.com> wrote: [SNIP]
----------------------------------------
<boost/io/streambuf_wrapping.hpp>:
I vote to reject, for the following reasons.
I don't accept the criticism that the proper way to use a custom streambuf is with a plain istream, ostream or iostream; it's nice to have matching stream classes to go with a custom stream buffer class.
However, if one has written a custom stream buffer, the name basic_wrapping_xstream is not what most people want for the matching streams. If the streambuf is called mapped_filebuf, a matching i/o stream might be named mapped_fstream. This could be solved with template aliases:
template<typename Ch> using mapped_fstream = basic_wrapping_iostream< mapped_filebuf<Ch> >;
Using streambuf_wrapping.hpp and the current language, the way to achieve this is to derive a stream class from basic_wrapping_iostream< mapped_filebuf<...> >:
template<typename Ch> class mapped_fstream : basic_wrapping_iostream<mapped_filebuf> { ... };
The problem with this is that one has to write new constructors, since they are not inherited. If one wants to follow the example of the standard library file and string streams, one should also repeat the typedefs char_type, traits_type, pos_type, etc. As a result, the above is scarcely easier than writing mapped_fstream from scratch, since writing the constructors (and typedefs) is the principle difficulty.
You didn't notice the extra "rdbuf" and "is_using_internal_streambuf" helper member functions? I admit that the examples basically are doing the repetition you're complaining about. But, it's better than nothing, right?
Without template aliases, a macro-based approach would be more useful:
#define BOOST_IO_DEFINE_WRAPPING_ISTREAM(stream, streambuf, arity) #define BOOST_IO_DEFINE_WRAPPING_OSTREAM(stream, streambuf, arity) #define BOOST_IO_DEFINE_WRAPPING_IOSTREAM(stream, streambuf, arity)
BOOST_IO_DEFINE_WRAPPING_ISTREAM(mapped_fstream, mapped_filebuf, 1)
You generally can't do a blind wrapping. Doing that prevents you from passing along the extra member functions from the stream buffer to the stream class.
Also, let me note that with my library, streams and stream buffers are generated simultaneously using stream_facade and streambuf_facade, so you will rarely need to write a stream buffer from scratch and wrap it in a stream. E.g.
struct tcp_resource { ... }; typedef streambuf_facade<tcp_resource> tcp_streambuf; typedef stream_facade<tcp_resource> tcp_stream;
Your framework and my wrappers work at different levels. Your framework is all about turning sources/sinks/filters into stream buffers. My wrappers only do a stream buffer to stream conversion. You have a stream facility too, but I guess it just does the main stream buffer conversion followed by a wrapping scheme similar to mine.
----------------------------------------
<boost/io/array_stream.hpp>:
I vote to reject, for the following reasons.
1. std::stringstream already writes to an internally managed character array, but it suffers from the following limitations (both resaonable in context)
a. You can't define a stringstream to access a region of memory specified in advance b. when you finish performing i/o, you can't get direct access to the underlying array.
array_stream addresses b but not a, and doesn't address b very well, since the lifetime of the array is included in the lifetime of the stream. I believe the pointer streams are better in every respect than the array streams.
There are times where you don't need the character buffer to be around outside the stream's lifetime. (The std::stringstream class has a similar limitation, except you can copy out the string easier.) In those cases, why bother allocating an array object outside the stream?
2. basic_array_streambuf should be implemented as a thin wrapper around basic_pointerbuf. Otherwise, you've got unnecessary code bloat, since all the code is duplicated for each value of N.
That's the inherent trade-off using compile-time arrays.
----------------------------------------
<boost/io/pointer_stream.hpp>:
I think pointer streams and stream buffers are moderately useful, and would vote for acceptance, but I have the following objections.
1. Having separate classes for const and non-const pointers leads to far too many templates. Const-correctness can be enforced by the stream buffer by not allowing constructors taking const char* to set the put area.
I deliberately didn't want that. The old std::strstream class has at least three distinct modes. It can act like std::stringstream, like pointerstream, or like iconstpointerstream. And I think it can sometimes switch between those behaviors in mid-use. I wanted separate classes for those uses, especially after the Standard only included one separation.
2. The interface is strange and poorly documented. For example, the specification of begin_pointer and end_pointer refer to the 'utilized array-segment'. What does this mean? Looking at the source, I see that they return pointer delimiting the get area, if the get area is valid, and pointers delimiting the put area otherwise. Why not simply make them return the pointers passed to the constructor, and call them begin and end? Together with the current seek positions -- available using pubseekoff -- this should give the user all the necessary information in a less confusing way. [TRUNCATE]
The "utilized array-segment" is the begin-end pair of pointers you passed in as the buffer. That pointer pair has to be either the get area, the put area, or both. That's why the functions returning the bounding pointers look in those areas; storing two extra pointer members would have been a waste of space. I don't call the functions "begin" or "end" because I don't want the stream to be directly useable as a STL-like container. The "?count" member functions can return the seek positions in a much faster way. -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

"Daryle Walker" <darylew@hotmail.com> wrote in message news:BD55AC50.E831%darylew@hotmail.com...
On 8/26/04 1:38 AM, "Jonathan Turkanis" <technews@kangaroologic.com> wrote:
<boost/io/streambuf_wrapping.hpp>:
I vote to reject, for the following reasons.
However, if one has written a custom stream buffer, the name basic_wrapping_xstream is not what most people want for the matching streams. If the streambuf is called mapped_filebuf, a matching i/o stream might be named mapped_fstream. This could be solved with template aliases:
The problem with this is that one has to write new constructors, since they are not inherited. If one wants to follow the example of the standard library file and string streams, one should also repeat the typedefs char_type, traits_type, pos_type, etc. As a result, the above is scarcely easier than writing mapped_fstream from scratch, since writing the constructors (and typedefs) is the principle difficulty.
You didn't notice the extra "rdbuf" and "is_using_internal_streambuf" helper member functions? I admit that the examples basically are doing the repetition you're complaining about. But, it's better than nothing, right?
Only marginally, I think. And for such a small benefit, I'm not sure it's worth making someone reading the code familiarize himself with a new template.
Without template aliases, a macro-based approach would be more useful:
#define BOOST_IO_DEFINE_WRAPPING_ISTREAM(stream, streambuf, arity) #define BOOST_IO_DEFINE_WRAPPING_OSTREAM(stream, streambuf, arity) #define BOOST_IO_DEFINE_WRAPPING_IOSTREAM(stream, streambuf, arity)
BOOST_IO_DEFINE_WRAPPING_ISTREAM(mapped_fstream, mapped_filebuf, 1)
You generally can't do a blind wrapping. Doing that prevents you from passing along the extra member functions from the stream buffer to the stream class.
Good point. I guess this show my biad in favor of keeping a lean open/is_open/close interface. But in general, you are right that more members may be needed.
Also, let me note that with my library, streams and stream buffers are generated simultaneously using stream_facade and streambuf_facade, so you will rarely need to write a stream buffer from scratch and wrap it in a stream. E.g.
struct tcp_resource { ... }; typedef streambuf_facade<tcp_resource> tcp_streambuf; typedef stream_facade<tcp_resource> tcp_stream;
Your framework and my wrappers work at different levels. Your framework is all about turning sources/sinks/filters into stream buffers. My wrappers only do a stream buffer to stream conversion. You have a stream facility too, but I guess it just does the main stream buffer conversion followed by a wrapping scheme similar to mine.
Yes, it's almost identical. It even uses base_from_member :-)
I vote to reject, for the following reasons.
1. std::stringstream already writes to an internally managed character array, but it suffers from the following limitations (both resaonable in context)
a. You can't define a stringstream to access a region of memory specified in advance b. when you finish performing i/o, you can't get direct access to the underlying array.
array_stream addresses b but not a, and doesn't address b very well, since the lifetime of the array is included in the lifetime of the stream. I believe the pointer streams are better in every respect than the array streams.
There are times where you don't need the character buffer to be around outside the stream's lifetime. (The std::stringstream class has a similar limitation, except you can copy out the string easier.) In those cases, why bother allocating an array object outside the stream?
Just to avoid having too many library components with overlapping functionality. You yourself say that array_stream is 'fairly uninteresting', but that it 'may have' real-life applications. Some reviewers found this rationale lacking last year. The fact that you still don't have a better rationale tells me that it should be rejected.
2. basic_array_streambuf should be implemented as a thin wrapper around basic_pointerbuf. Otherwise, you've got unnecessary code bloat, since all the code is duplicated for each value of N.
That's the inherent trade-off using compile-time arrays.
There's no trade-off, that I see. Using a wrapper around pointerbuf reduces code bloat but should have no adverse performance impact. Right?
----------------------------------------
<boost/io/pointer_stream.hpp>:
I think pointer streams and stream buffers are moderately useful, and would vote for acceptance, but I have the following objections.
1. Having separate classes for const and non-const pointers leads to far too many templates. Const-correctness can be enforced by the stream buffer by not allowing constructors taking const char* to set the put area.
I deliberately didn't want that. The old std::strstream class has at least three distinct modes. It can act like std::stringstream, like pointerstream, or like iconstpointerstream. And I think it can sometimes switch between those behaviors in mid-use. I wanted separate classes for those uses, especially after the Standard only included one separation.
I know. The problem with strstream is that it does too much. It's good to get rid of allocation functions. But the didea of a stream which can be opened in read-only, write-only or read-write mode is very familiar. It's much better than multiplying the number of templates by 2.
2. The interface is strange and poorly documented. For example, the specification of begin_pointer and end_pointer refer to the 'utilized array-segment'. What does this mean? Looking at the source, I see that they return pointer delimiting the get area, if the get area is valid, and pointers delimiting the put area otherwise. Why not simply make them return the pointers passed to the constructor, and call them begin and end? Together with the current seek positions -- available using pubseekoff -- this should give the user all the necessary information in a less confusing way. [TRUNCATE]
The "utilized array-segment" is the begin-end pair of pointers you passed in as the buffer. That pointer pair has to be either the get area, the put area, or both. That's why the functions returning the bounding pointers look in those areas; storing two extra pointer members would have been a waste of space.
I didn't say to store the pointers. Aha ... I see ... you're implementation is just the natural way to recover the pointers, right?
I don't call the functions "begin" or "end" because I don't want the stream to be directly useable as a STL-like container.
The "?count" member functions can return the seek positions in a much faster way.
Faster because there's no virtual function call? Jonathan

On 8/28/04 4:05 PM, "Jonathan Turkanis" <technews@kangaroologic.com> wrote:
"Daryle Walker" <darylew@hotmail.com> wrote in message news:BD55AC50.E831%darylew@hotmail.com...
On 8/26/04 1:38 AM, "Jonathan Turkanis" <technews@kangaroologic.com> wrote: [SNIP]
However, if one has written a custom stream buffer, the name basic_wrapping_xstream is not what most people want for the matching streams. If the streambuf is called mapped_filebuf, a matching i/o stream might be named mapped_fstream. This could be solved with template aliases:
The problem with this is that one has to write new constructors, since they are not inherited. If one wants to follow the example of the standard library file and string streams, one should also repeat the typedefs char_type, traits_type, pos_type, etc. As a result, the above is scarcely easier than writing mapped_fstream from scratch, since writing the constructors (and typedefs) is the principle difficulty.
You didn't notice the extra "rdbuf" and "is_using_internal_streambuf" helper member functions? I admit that the examples basically are doing the repetition you're complaining about. But, it's better than nothing, right?
Only marginally, I think. And for such a small benefit, I'm not sure it's worth making someone reading the code familiarize himself with a new template.
It's like the dilemma: "It's so easy, you can write it yourself." "If it's so easy, why can't you include a version?" If everyone has to do it themselves, then we'll get a whole bunch of slightly different version. And some may have bugs. If the original source does it, then only that source has to do debugging. And everyone benefits from the one set of source code improving. [SNIP]
2. basic_array_streambuf should be implemented as a thin wrapper around basic_pointerbuf. Otherwise, you've got unnecessary code bloat, since all the code is duplicated for each value of N.
That's the inherent trade-off using compile-time arrays.
There's no trade-off, that I see. Using a wrapper around pointerbuf reduces code bloat but should have no adverse performance impact. Right?
But you would have to manually define a pointer-stream and an array as two separate objects, then connect them together. Using a class to automate the process would give similar results to my array-stream. Forcing the user to manually create code as an alternative to having a piece of pre-existing "bloat"-like code is _not_ generally a gain. [SNIP]
1. Having separate classes for const and non-const pointers leads to far too many templates. Const-correctness can be enforced by the stream buffer by not allowing constructors taking const char* to set the put area.
I deliberately didn't want that. The old std::strstream class has at least three distinct modes. It can act like std::stringstream, like pointerstream, or like iconstpointerstream. And I think it can sometimes switch between those behaviors in mid-use. I wanted separate classes for those uses, especially after the Standard only included one separation.
I know. The problem with strstream is that it does too much. It's good to get rid of allocation functions. But the didea of a stream which can be opened in read-only, write-only or read-write mode is very familiar. It's much better than multiplying the number of templates by 2.
The pointer stream and its pointer-to-const variant have different semantics. Shoving the const variant into the main one would be a repeat of the std::strstream mess. Wouldn't you want a mistake in building constructor arguments cause an error directly instead of activating a different, unwanted set of semantics? [SNIP]
The "?count" member functions can return the seek positions in a much faster way.
Faster because there's no virtual function call?
Yes. -- Daryle Walker Mac, Internet, and Video Game Junkie darylew AT hotmail DOT com

"Daryle Walker" <darylew@hotmail.com> wrote in message:
On 8/28/04 4:05 PM, "Jonathan Turkanis" <technews@kangaroologic.com> wrote:
"Daryle Walker" <darylew@hotmail.com> wrote in message news:BD55AC50.E831%darylew@hotmail.com...
On 8/26/04 1:38 AM, "Jonathan Turkanis" <technews@kangaroologic.com> wrote:
Only marginally, I think. And for such a small benefit, I'm not sure it's worth making someone reading the code familiarize himself with a new template.
It's like the dilemma: "It's so easy, you can write it yourself." "If it's so easy, why can't you include a version?"
Right. :-)
If everyone has to do it themselves, then we'll get a whole bunch of slightly different version. And some may have bugs. If the original source does it, then only that source has to do debugging. And everyone benefits from the one set of source code improving.
Maybe. Looking at the implementation of streambuf_wrapping, I'm not sure why it has to be so complicated. Could you explain why you need basic_wrapping_ios and virtual inheritance?
[SNIP]
2. basic_array_streambuf should be implemented as a thin wrapper around basic_pointerbuf. Otherwise, you've got unnecessary code bloat, since all the code is duplicated for each value of N.
That's the inherent trade-off using compile-time arrays.
There's no trade-off, that I see. Using a wrapper around pointerbuf reduces code bloat but should have no adverse performance impact. Right?
But you would have to manually define a pointer-stream and an array as two separate objects, then connect them together. Using a class to automate the process would give similar results to my array-stream. Forcing the user to manually create code as an alternative to having a piece of pre-existing "bloat"-like code is _not_ generally a gain.
I was thinking of something like this (simplified and untested): template<size_t N> class arraybuf : pointerbuf { public: arraybuf() : pointerbuf(data, data + N) { } arraybuf(const char* first, const char* last) : pointerbuf(data, data + N) { assert(last - first <= N); std::copy(first, last, data); } template<typename InIt> arraybuf(InIt first, InIt last); [some other stuff, but no need to override the virtual functions] private: char data[N]; }; This doesn't require the user to create the array separately.
The pointer stream and its pointer-to-const variant have different semantics.
Is there any difference other than the fact that you can't write to a const char*?
[SNIP]
The "?count" member functions can return the seek positions in a much faster way.
Faster because there's no virtual function call?
Yes.
But is this something that needs to be optimized? My heuristic for i/o is that any operation which might be performed for each character in a sequence must be highly optimized, but that operations which occur only once in a while, say each time a buffer fills up, can afford a virtual function call or two. Can you think of a scenario in which pubseekoff would be called so frequently that it would become a performance bottleneck? If so, I still think gcount and pcount are poorly named, since for streams the members with these names return the number of characters processed in the most recent i/o operation. I'd prefer if they were called tellg and tellp. Best Regards, Jonathan

| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of tom brinkman | Sent: 21 August 2004 15:09 | To: boost@lists.boost.org | Subject: [boost] Review of Daryle Walker's "More IO" library | What is your evaluation of the design? No obvious problems that I am qualified to judge. | What is your evaluation of the implementation? No obvious problems that I am qualified to judge. | What is your evaluation of the documentation? Formal documentation and testing look satisfactory - at a glance. But the documentation won't sell it to the users - they MUST have tutorials and EXAMPLES, even if many of uses appear trivially simple to the cognescenti. I'd like to see these as a condition of final acceptance. | What is your evaluation of the potential usefulness of the library? Useful (some very useful), but filtering elements are potentially even more valuable. None that are bad idea - though some more useful than others - subjective? | Did you try to use the library? No, but I have used parts previously. | How much effort did you put into your evaluation? Minor - a quick re-reading. | Are you knowledgeable about the problem domain? Not very - but as a user I feel the need for many items. | Do you think the library should be accepted as a Boost library? Yes, but it must work with Jonathan Turkanis's forthcoming further IO contribution. Paul PS In the collection of questions to be answered in reviews, I feel we could usefully separately assess the TESTING from the docs. There is also often a need for both a formal description, and for user friendly tutorial and examples. I feel we should be assessing ALL these elements separately. For many Boost authors, it is not worth producing some of these items unless one is confident of ultimate acceptance. Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539 561830 +44 7714 330204 mailto: pbristow@hetp.u-net.com

| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Paul A Bristow | Sent: 26 August 2004 15:47 | To: boost@lists.boost.org | Subject: RE: [boost] Review of Daryle Walker's "More IO" | library begins today,August 21, 2004. I am aware it is too late for this review, but I have recently been re-building some examples using MSVC 8.0, (with mixed success) and one of them is the newl function re-proposed by Daryle. (I can't remember who originally proposed this function - but he was highly reputable ;-) To recap, there was some query on how useful this was.
From a very naïve test of a lot of new lines, I can report:
1 MSVC 8.0 seems significantly faster (unless I have missed something). 2 A newline as /n or using newl costs twice as much as a normal alphachar - because it does cr lf?? 3 A C string "/n" takes only the same as a single char. 3 endl takes 10 times as long - for the flush? 4 These times are NOW the same for sending to files and to cout (previously much slower to cout). Obviously, one doesn't only send newlines, but I still believe one can conclude: A newl is conceptionally correct over endl - it doesnt flush unncessarily. B newl offers a slight performance advantage over endl. C ensuring that your newlines are embedded/concatenated into C strings where possible is best of all. So writing cout << "Line1" "/n" // concatentates. Is more to type but clearer? "Line2/n" // idle typists may prefer? "\n" "Line 3" // Not So clear? "Line 4" << newl // Clear but less efficient. << endl; // Only if a final flush is required. is faster and clearer than: cout << "Line1" << endl << "Line2" << endl ... So I still believe that function newl is the Right Thing To Do. Paul Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB +44 1539 561830 +44 7714 330204 mailto: pbristow@hetp.u-net.com
participants (9)
-
Daniel James
-
Darren Cook
-
Daryle Walker
-
David Abrahams
-
Jonathan Turkanis
-
Paul A Bristow
-
Pavel Vozenilek
-
Rob Stewart
-
tom brinkman