bufferstreamの話

前回のvectorstreamと同じで、interprocessのstreamsのもう1つ、bufferstreamの話。

bufferstream?

"buffer"については皆さんが普段思ってる通りで良いと思います。何かしらのデータを溜めておくための領域。bufferstreamは固定サイズバッファにデータを読み書きするためのiostreamベースなクラスです。テンプレート引数はバッファの型(CharT)とその型に対するtraits(CharTraits)です。こちらはデフォルトで利用できるtypedefがあります。

template<class CharT, class CharTraits = std::char_traits<CharT>>
class basic_bufferstream  : public std::basic_iostream<CharT, CharTraits>
template<class CharT, class CharTraits = std::char_traits<CharT>>
class basic_ibufferstream : public std::basic_istream<CharT, CharTraits>
template<class CharT, class CharTraits = std::char_traits<CharT>>
class basic_obufferstream : public std::basic_ostream<CharT, CharTraits>

typedef basic_bufferstream<char>     bufferstream;
typedef basic_ibufferstream<char>    ibufferstream;
typedef basic_obufferstream<char>    obufferstream;
typedef basic_bufferstream<wchar_t>  wbufferstream;
typedef basic_ibufferstream<wchar_t> wibufferstream;
typedef basic_obufferstream<wchar_t> wobufferstream;

固定サイズバッファへの書き込みができるのですが、オーバーフローしてるかどうかのチェックもできます。vectorstreamと同じで内部で使っているバッファを取得できるようにbufferメソッドがあります。これはバッファへのポインタとバッファのサイズをpairで取得できます。またオーバーロードされており、バッファを設定し直すことができます。

namespace bip = boost::interprocess;

static std::size_t const size = 100;
char arr[size]
bip::bufferstream bstream(arr,size);

auto i = bstream.buffer();
BOOST_ASSERT(i.first == arr);
BOOST_ASSERT(i.second == size);

static std::size_t const new_size = 10;
char new_arr[new_size];
bstream.buffer(new_arr,new_size);

auto i = bstream.buffer();
BOOST_ASSERT(!(i.first == arr));
BOOST_ASSERT(!(i.second == size));

入出力方法はvectorstream同様iostreamベースなのでそこまで変わりません。

#include <boost/interprocess/streams/bufferstream.hpp>
#include <boost/range/algorithm/for_each.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/range/algorithm/equal.hpp>
#include <boost/range/algorithm_ext/iota.hpp>>
#include <boost/range/istream_range.hpp>
#include <vector>
#include <iostream>

void stream_test();

int main()
{
    try {
        stream_test();
    } catch( std::exception& e ) {
        std::cerr << e.what() << std::endl;
        return -1;
    }
}

void stream_test()
{
    namespace bip = boost::interprocess;

    static const std::size_t Size		= 100;
    static const std::size_t BufferSize = Size * 5;
    std::vector<int> data(Size);
    boost::iota(data,0);
	
    // バッファの作成
    char Buffer[BufferSize];
    bip::bufferstream buffer_stream(Buffer, BufferSize);
    {
        auto const i = buffer_stream.buffer();
        BOOST_ASSERT(i.first  == Buffer);
        BOOST_ASSERT(i.second == BufferSize);
    }
    boost::for_each(data,[&buffer_stream](int i){ buffer_stream << i << " "; });
    BOOST_ASSERT(buffer_stream.good());

    // 全て読み出し
    std::vector<int> data2;
    boost::copy(boost::istream_range<int>(buffer_stream),std::back_inserter(data2));
    BOOST_ASSERT(buffer_stream.fail());
    BOOST_ASSERT(boost::equal(data,data2));
}

バッファサイズを固定して書き込みたい場合はvectorstreamよりbufferstreamの方が良い、という風にドキュメントにも書かれているようです。ファイルイメージをコピーしたいときなどに使うんでしょうか。もしくはサイズが制限されている時など。interprocessが共有メモリを使うためのライブラリですから、本来の目的で使用している場合は結構使う場面は多いのかもしれません。