Skip to content

Instantly share code, notes, and snippets.

@alzobnin
Last active October 20, 2020 09:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alzobnin/262c7038ac50ed3596e5c5bfb6858e86 to your computer and use it in GitHub Desktop.
Save alzobnin/262c7038ac50ed3596e5c5bfb6858e86 to your computer and use it in GitHub Desktop.

Разбор задачи «Буферизованный вывод»

Условие

Вам дан класс Writer, который умеет писать данные на экран, в файл или в память – в общем, неважно куда. У этого класса есть виртуальная функция Write, принимающая на вход указатель на байты памяти и их количество. Функция пытается записать эти байты в нужное место. Выглядит этот класс примерно так:

class Writer {
public:
    virtual void Write(const char * data, size_t len) {
        // Какой-то вывод в файл, на экран или в память
    }
};

Однако операция вывода имеет накладные расходы, и частые вызовы Write с маленькими размерами данных могут замедлять программу. Вам надо написать класс-наследник BufferedWriter, который осуществлял бы буферизованный вывод. Конструктор этого класса должен принимать параметр типа size_t – размер буфера. Переопределенная в этом классе функция Write должна сначала дописывать данные в этот внутренний буфер, и только когда он заполнится – вызывать Write базового класса с данными этого буфера. В конце использования класса оставшиеся в буфере данные также должны быть записаны через вызов функции Write базового класса. Максимально возможный размер буфера, переданный в конструкторе, в процессе работы не должен изменяться.

Начните свою программу с #include "writer.h" – эта директива подключит нашу версию базового класса Writer. Далее напишите только код класса-наследника BufferedWriter.

Решение

Будем в качестве буфера использовать vector<char>. В конструкторе установим зарезервированную ёмкость вектора равной размеру буфера, и не будем дальше её менять. Функция Write будет помещать в конец вектора очередной кусок данных, лишь бы он поместился в вектор. Если вектор заполнился, вызовем вспомогательную функцию Flush, обращающуюся к функции Write базового класса. Важно не забыть вызвать Flush в деструкторе нашего класса, так как в буфере могли остаться какие-то данные.

#include "writer.h"

#include <algorithm>  // for std::min
#include <vector>

class BufferedWriter: public Writer {
private:
    std::vector<char> buffer;

public:
    BufferedWriter(size_t bufsize) {
        buffer.reserve(bufsize);
    }

    void Write(const char* data, size_t len) override {
        size_t pos = 0;
        while (pos != len) {
            auto chunk = std::min(len - pos, buffer.capacity() - buffer.size());
            buffer.insert(buffer.end(), data + pos, data + pos + chunk);
            pos += chunk;
            if (buffer.size() == buffer.capacity()) {
                Flush();
            }
        }
    }

    void Flush() {
        Writer::Write(buffer.data(), buffer.size());
        buffer.clear();
    }

    ~BufferedWriter() {
        Flush();
    }
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment