arbitrary_positional_facade

位置復元可能ストリームを元に任意位置ストリームを生成するヘルパクラスを作成しました。

namespace hamigaki { namespace iostreams {

template<class Derived, class CharT, std::streamsize MaxBlockSize>
class arbitrary_positional_facade;

// iterator_core_accessと同じ役割
class core_access
{
#if defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
public:
#else
    template<class Derived, class CharT, std::streamsize MaxBlockSize>
    friend class arbitrary_positional_facade;
#endif

    template<class RepositionalSource, class CharT>
    static std::streamsize read_blocks(
        RepositionalSource& src, CharT* s, std::streamsize n)
    {
        return src.read_blocks(s, n);
    }

    template<class RepositionalSink, class CharT>
    static std::streamsize write_blocks(
        RepositionalSink& sink, const CharT* s, std::streamsize n)
    {
        return sink.write_blocks(s, n);
    }
};

template<class Derived, class CharT, std::streamsize MaxBlockSize>
class arbitrary_positional_facade
{
private:
    typedef CharT char_type;

    Derived& derived()
    {
      return *static_cast<Derived*>(this);
    }

protected:
    // 派生クラスからアクセスしやすいように
    typedef arbitrary_positional_facade<
        Derived,CharT,MaxBlockSize> arbitrary_positional_facade_;

public:
    explicit arbitrary_positional_facade(std::streamsize block_size)
        : block_size_(block_size), count_(0)
    {
    }

    std::streamsize read(char_type* s, std::streamsize n)
    {
        if ((count_ == 0) && ((n % block_size_) == 0))
            return core_access::read_blocks(derived(), s, n/block_size_);
        else
        {
            // 略
        }
    }

    std::streamsize write(const char_type* s, std::streamsize n);

private:
    char_type buffer_[MaxBlockSize];
    std::streamsize block_size_;
    std::streamsize count_; // バッファに格納されている文字数
};

} } // End namespaces iostreams, hamigaki.

これを使って、

class my_sink
    : public hamigaki::iostreams::arbitrary_positional_facade<my_sink, char, 4>
{
    // write_blocks()にアクセスできるようにする
    friend class hamigaki::iostreams::core_access;

public:
    explicit my_sink(const pcm_format& f)
        : arbitrary_positional_facade(f.block_size())
    {
    }

private:
    // 直接呼ばれるとバッファリングが狂うのでprivateにする
    std::streamsize write_blocks(const char* s, std::streamsize n)
    {
        // nブロック書き出す
    }

とすると、write_blocks()からバッファリング付きのwrite()が導出されます。
以下、TODO。

  • seek()のサポート
  • Seekableのように入力と出力でヘッドを共有している場合は、read()とwrite()で同期を取る
  • Bidirectionalの場合はバッファを2つ用意する

modeによって場合分けが発生するのがBoost.Iostreamsの面倒なところです。