Предоставить интерфейс std :: istream для существующего буфера, не копируя его - PullRequest
11 голосов
/ 20 марта 2011

У меня есть буфер символов фиксированной длины, и я хотел бы передать его функции, которая принимает std :: istream &. Как я могу сделать это без копирования буфера?

Если это означает получение пользовательского streambuf, я думаю, что я буду жить с копией. Мне просто интересно, упускаю ли я что-то прямое.

Вот что я делаю сейчас (что делает нежелательную копию):

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

Edit:

Для справки, вот простое решение с использованием 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, потому что он кажется «правильным» решением, однако он не компилируется на моей платформе (Android NDK), поэтому я решил использовать устаревшее решение std :: istrstream. Спасибо всем.

Ответы [ 3 ]

7 голосов
/ 20 марта 2011

Я сам был в подобной ситуации, и вместо того, чтобы создавать все сам, я использовал 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;
1 голос
/ 20 марта 2011

Я сомневаюсь, что это возможно. Контейнеры / потоки STL и т. Д. Всегда хотят иметь буфер, поэтому они его копируют. Там нет простого способа, о котором я знаю.

1 голос
/ 20 марта 2011

Одним из вариантов будет предоставление пользовательской реализации std::streambuf, которая ссылается на внешний (а не внутренний) буфер.Получив это, вы можете создать подкласс из std::istream и предоставить конструктор, который устанавливает потоковый буфер istream в качестве экземпляра вашего пользовательского типа streambuf, который указывает на ваш буфер.Это сразу дает вам все возможности istream, которые будут поддерживаться вашим внешним буфером.IIRC, большая часть сложности реализации streambuf включает в себя сложности повторного заполнения буфера, когда в нем заканчиваются данные, но в вашем случае это должно быть тривиально, поскольку вы можете просто сообщить, что у вас нет данных.

Надеюсь, это поможет!

...