2011-03-20 10 views
11

私は固定長のchar型のバッファを持っており、std :: istreamを取る関数にフィードしたいのです&。バッファをコピーせずにどうすればいいですか?既存のバッファへのstd :: istreamインタフェースをコピーせずに提供する

カスタムストリームビルドを派生させることを意味するなら、私はそのコピーで暮らすと思います。私は何かが簡単に欠けているのだろうかと思っています。ここで

は(不要なコピーをしている)私が今やっているものです:

void loadFromBuffer(const char* buff, size_t len) { 
    std::istringstream is(std::string(buff, len)); // BUFFER COPIED HERE :(
    load(is); 
} 

は編集:

記録のために、ここでboost.Iostreamsを使用して簡単な解決策があります:

#include <boost/iostreams/device/array.hpp> 
#include <boost/iostreams/stream.hpp> 

void loadFromBuffer2(char* buff, size_t len) { 
    typedef boost::iostreams::stream<boost::iostreams::array_source> array_stream; 
    array_stream is(buff, len); 
    load(is); 
} 

私はBoost.Iostreamsの回答を受け入れました。なぜなら、 "正しい"解決策であると思われるからです。しかし、oはコンパイルされません。私のプラットフォーム(Android NDK)では、廃止予定のstd :: istrstreamソリューションを使用してしまいました。みんな、ありがとう。

+0

あなたは離れて、この場合、最適化されていなかったコピーをチェックしましたか? – log0

+1

ちょうどあなたの情報のために、 'std :: istrstream'はこの機能を提供します。 コンストラクタ '(char *、streamsize)'を持っています。 しかし、ご存知のとおり、このクラスは非推奨です... –

答えて

7

自分でも同様の状況になりましたが、自分ですべてを作成するのではなく、Boost.Iostreamsを使用して読み取り専用ソースデバイスを作成しました。

テストされていないが、これは動作することがあります。

class ConstBufferDevice 
{ 
public: 
    typedef char char_type; 

    struct category : 
     virtual boost::iostreams::device_tag, 
     virtual boost::iostreams::input_seekable 
    { 
    }; 

    ConstBufferDevice(const char_type* buffer, size_t buffersize) 
     : buffer_(buffer) 
     , buffersize_(buffersize) 
     , pos_(0) 
    { 
    } 

    std::streamsize read(char_type* buffer, std::streamsize buffersize) 
    { 
     const std::streamsize amount = static_cast<std::streamsize>(buffersize_ - pos_); 
     const std::streamsize result = (std::min)(buffersize, amount); 
     if (result != 0) 
     { 
     std::copy(buffer_ + pos_, buffer_ + pos_ + result, buffer); 
     pos_ += result; 
     return result; 
     } 
     else 
     { 
     return buffersize ? -1 : 0; // EOF 
     } 
    } 

    std::streampos seek(boost::iostreams::stream_offset offset, 
         std::ios_base::seekdir seekdir) 
    { 
     // Determine new value of pos_ 
     boost::iostreams::stream_offset newpos; 

     if (seekdir == std::ios_base::beg) 
     { 
     newpos = offset; 
     } 
     else if (seekdir == std::ios_base::cur) 
     { 
     newpos = pos_ + offset; 
     } 
     else if (seekdir == std::ios_base::end) 
     { 
     newpos = buffersize_ + offset; 
     } 
     else 
     { 
     throw std::ios_base::failure("bad seek direction"); 
     } 

     // Check for errors 
     if (newpos < 0 || newpos > buffersize_) 
     { 
     throw std::ios_base::failure("bad seek offset"); 
     } 

     pos_ = static_cast<size_t>(newpos); 
     return boost::iostreams::offset_to_position(newpos); 
    } 

private: 
    const char_type* buffer_; 
    size_t buffersize_; 
    size_t pos_; 
}; 

typedef boost::iostreams::stream<ConstBufferDevice> ConstBufferStream; 
+0

提案していただきありがとうございます。コードに関しては、ライブラリはすでにこの機能を提供していませんか?私は[boost :: iostreams :: array_source](http://www.boost.org/doc/libs/1_46_1/libs/iostreams/doc/index)を見ていました。html)、ドキュメントのクイックスキムでは同じことをするように見えます。たぶん私は何かが欠けているでしょう。 –

+0

@Martin Stone:私の解決策は、あなたの 'array_source'は私の解決策が見つけられるということではありません。それを必要としない場合は、 'array_source'を実行してください。 – dalle

+0

@dalle内部バッファにポインタを戻す方法はありますか? (私のための特別なケース)バッファで利用できる有効な(書かれた)データを調べるのはどうですか? – Ghita

1

1つのオプションは、外部(内部ではなく)バッファを参照するカスタム実装std::streambufを提供することです。これを取得したら、std::istreamからサブクラス化し、istreamのストリームバッファを、自分のバッファを指すカスタムstreambufタイプのインスタンスに設定するコンストラクタを提供します。これによりすぐに外部バッファによってバックアップされるistreamの全機能が提供されます。 IIRCの場合、streambufを実装する複雑さの大部分は、データがなくなったときにバッファを補充するという複雑さが伴いますが、データが不足していると報告できるだけなので、些細なことが必要です。

希望すると便利です。

+0

OPはstd :: streambufをサブクラス化したくありません。 –

+0

@dark_charlie:これは 'streambuf'をサブクラス化せずにはできないと確信しています。この答えの要点は、当初のようには難しくないとは思わないということです。 – templatetypedef

+0

それでも、コピーがはるかに簡単で、バッファーが大きくなければパフォーマンスの問題はごくわずかです。 –

1

これは可能でしょうか。 STLコンテナ/ストリームなどは常にバッファを所有したいので、それをコピーします。私が気づいている簡単な方法はありません。

関連する問題