Maneira mais simples de criar um stream de memory C ++ de (char *, tamanho_t), sem copiar os dados?

Eu não consegui encontrar nada pronto, então eu inventei:

class membuf : public basic_streambuf { public: membuf(char* p, size_t n) { setg(p, p, p + n); setp(p, p + n); } } 

Uso:

 char *mybuffer; size_t length; // ... allocate "mybuffer", put data into it, set "length" membuf mb(mybuffer, length); istream reader(&mb); // use "reader" 

Eu sei de stringstream , mas não parece ser capaz de trabalhar com dados binários de comprimento determinado.

Eu estou inventando minha própria roda aqui?

EDITAR

  • Não deve copiar os dados de input, basta criar algo que irá iterar sobre os dados.
  • Ele deve ser portátil – pelo menos, deve funcionar tanto no gcc quanto no MSVC.

Estou assumindo que seus dados de input são binários (não texto) e que você deseja extrair partes de dados binários dele. Tudo sem fazer uma cópia dos seus dados de input.

Você pode combinar boost::iostreams::basic_array_source e boost::iostreams::stream_buffer (de Boost.Iostreams ) com boost::archive::binary_iarchive (de Boost.Serialization ) para poder usar operadores de extração >> convenientes para ler pedaços de dados binários.

 #include  #include  #include  #include  #include  int main() { uint16_t data[] = {1234, 5678}; char* dataPtr = (char*)&data; typedef boost::iostreams::basic_array_source Device; boost::iostreams::stream_buffer buffer(dataPtr, sizeof(data)); boost::archive::binary_iarchive archive(buffer, boost::archive::no_header); uint16_t word1, word2; archive >> word1 >> word2; std::cout << word1 << "," << word2 << std::endl; return 0; } 

Com o GCC 4.4.1 no AMD64, ele gera:

1234,5678

Boost.Serialization é muito poderoso e sabe como serializar todos os tipos básicos, seqüências de caracteres e até mesmo contêineres STL. Você pode facilmente tornar seus tipos serializáveis. Veja a documentação. Oculto em algum lugar nas fonts Boost.Serialization é um exemplo de um arquivo binário portátil que sabe como executar a troca adequada para o endianness de sua máquina. Isso pode ser útil para você também.

Se você não precisa da imaginação do Boost.Serialization e está feliz em ler os dados binários em um estilo fread (), você pode usar basic_array_source de uma forma mais simples:

 #include  #include  #include  #include  int main() { uint16_t data[] = {1234, 5678}; char* dataPtr = (char*)&data; typedef boost::iostreams::basic_array_source Device; boost::iostreams::stream stream(dataPtr, sizeof(data)); uint16_t word1, word2; stream.read((char*)&word1, sizeof(word1)); stream.read((char*)&word2, sizeof(word2)); std::cout << word1 << "," << word2 << std::endl; return 0; } 

Eu recebo a mesma saída com este programa.

Não tenho certeza do que você precisa, mas isso faz o que você quer?

 char *mybuffer; size_t length; // allocate, fill, set length, as before std::string data(mybuffer, length); std::istringstream mb(data); //use mb 

O buffer de stream padrão possui essa funcionalidade.
Crie um stream. Obtém seu buffer, em seguida, substitui-lo.

 #include  #include  #include  #include  int main() { // Your imaginary buffer char buffer[] = "A large buffer we don't want to copy but use in a stream"; // An ordinary stream. std::stringstream str; // Get the streams buffer object. Reset the actual buffer being used. str.rdbuf()->pubsetbuf(buffer,sizeof(buffer)); std::copy(std::istreambuf_iterator(str), std::istreambuf_iterator(), std::ostream_iterator(std::cout) ); } 

O questionador queria algo que não copia os dados e sua solução funciona bem. Minha contribuição é limpá-lo um pouco, para que você possa criar um único object que seja um stream de input de dados na memory. Eu testei isso e funciona.

 class MemoryInputStream: public std::istream { public: MemoryInputStream(const uint8_t* aData,size_t aLength): std::istream(&m_buffer), m_buffer(aData,aLength) { rdbuf(&m_buffer); // reset the buffer after it has been properly constructed } private: class MemoryBuffer: public std::basic_streambuf { public: MemoryBuffer(const uint8_t* aData,size_t aLength) { setg((char*)aData,(char*)aData,(char*)aData + aLength); } }; MemoryBuffer m_buffer; }; 
Intereting Posts