From: Maxim Egorushkin (e-maxim_at_[hidden])
Date: 2003-05-04 09:15:35


Hi, all.

I've written std::streambuf<> adapters and I think you might find it
useful enough to include it in boost.

The main idea is simple: make implementation of custom streambuf easier.
This is done by obviating the user from buffer memory management and by
presenting more simple then std::basic_streambuf<> interface to the
controled sequence (sequence model) for the user to implement.

Here is the synosis of it:

<code>
namespace sequence_buffer
{

// adaptable sequence concepts
template<class model> class input_sequence_concept;
template<class model> class output_sequence_concept;

// examples of sequence models
template<class iterator> class stl_input_sequence;
template<class iterator> class stl_output_sequence;
template<class container> class push_back_sequence;

// named optional parameters for buffer adapters
template<class T> struct allocator_is;
template<class T> struct element_is;
template<class T> struct element_traits_is;
template<size_t size> struct buffer_size_is;

namespace detail { struct default_parameter; }

// buffer adapters
template<
        // mandatory parameters
                class sequence_model
        // optional parameters
        , class P1 = detail::default_parameter
        , class P2 = detail::default_parameter
        , class P3 = detail::default_parameter
        , class P4 = detail::default_parameter
>
class input_buffer;

template<
        // mandatory parameters
                class sequence_model
        // optional parameters
        , class P1 = detail::default_parameter
        , class P2 = detail::default_parameter
        , class P3 = detail::default_parameter
        , class P4 = detail::default_parameter
>
class output_buffer;

} // namespace sequence_buffer
</code>

I implemented 3 examples of the sequence model: stl_input_sequence<>,
stl_output_sequence<>, push_back_sequence<>. I don't think they are
quite useful but they are good as examples.

Here is the example of usage (useless but clear):

<code>
#include <iostream>
#include <algorithm>
#include <vector>

#include "sequence_buffer.hpp"

int main()
{
        using namespace std;
        namespace sb = sequence_buffer;

        vector<char> v1;

        // make an output buffer from the vector
        typedef sb::push_back_sequence<vector<char> > seq1;
        seq1 s1(v1);
        sb::output_buffer<seq1> b1(s1);

        // redirect cout to the buffer
        basic_streambuf<char>* cout_buf = cout.rdbuf(&b1);

        cout << "Redirect this text" << endl;

        // make an input buffer from the vector
        typedef sb::stl_input_sequence<vector<char>::const_iterator>
seq2;
        seq2 s2(v1.begin(), v1.end());
        sb::input_buffer<seq2> b2(s2);

        // copy the input buffer-vector to the original cout buffer
        copy(istreambuf_iterator<char>(&b2),
istreambuf_iterator<char>(),
                ostreambuf_iterator<char>(cout_buf));

        cout.rdbuf(cout_buf);

        return 0;
}
</code>

Of course, in a real project I made more conscious use of it: I use the
adapters to make ftp files look like std::streambuf<>.

The buffer adapters have optional parameters: element type (default is
char), element traits (default is std::char_traits<element>), buffer
size (default is 0x100 elements) and buffer memory allocator (default is
std::allocator<element>). When parametrizing a buffer adapter the
parameters can be specified in any orded (the idea comes from boost
iterator adapters library):

<code>
typedef output_buffer<my_sequence, element_is<wchar_t> > buf1;
typedef output_buffer<my_sequence, buffer_size_is<0x4000>,
allocator_is<my_allocator<wchar_t> >, element_is<wchar_t> > buf2;
</code>

The code uses boost mpl library and type traits. It was written using MS
VC++ 7.1 and tested on gcc 3.2.

That's all.

Thank you for reading to this point,
Maxim Egorushkin.