Реализовать класс MemoryStream для работы с памятью как с потоком ввода/вывода.
Реализовать класс MemoryStream в соответствии с приведённым ниже интерфейсом.
//MemoryStream.hpp
#include <cstdint> // uint8_t
#include <cstdio>
enum OpenMode : uint8_t
{
Read = 0x01, // разрешает операции чтения из потока
Write = 0x02, // разрешает операции записи в поток
};
enum IOState : uint8_t
{
Good = 0x00, // нет ошибок
EoF = 0x01, // при чтении достигнут конец потока
Bad = 0x02, // ошибка ввода-вывода
};
enum SeekDirection : int
{
Begin = SEEK_SET,
Current = SEEK_CUR,
End = SEEK_END,
};
class MemoryStream final
{
public:
MemoryStream();
explicit MemoryStream(const char* name, uint8_t mode);
~MemoryStream();
public:
// объекты класса stream нельзя копировать:
MemoryStream(const MemoryStream&) = delete;
MemoryStream& operator=(const MemoryStream&) = delete;
public:
const char* str();
void str(const char* s);
void swap(MemoryStream& memoryStream);
public:
uint8_t state();
void clearState();
public:
bool good();
bool eof();
bool bad();
public:
size_t count();
public:
MemoryStream& ignore(size_t n = 1, int delim = EOF);
public:
MemoryStream& read(void* buffer, size_t size);
MemoryStream& write(const void* buffer, size_t size);
public:
int get();
MemoryStream& get(char& c);
MemoryStream& get(char* s, size_t len);
MemoryStream& put(char c);
MemoryStream& put(const char* s, size_t len);
public:
MemoryStream& print(const char* format, ...);
public:
fpos_t pos();
MemoryStream& pos(fpos_t p);
long int tell();
MemoryStream& seek(long int offset, SeekDirection dir);
private:
// поля...
};
Для public и protected методов класса не допускается изменение названий, а также типов и количества аргументов.
Однако, в приведённых фрагментах кода намеренно опущен ряд спецификаторов const и static.
При реализации необходимо вернуть их на место в соответствии с логикой работы класса.
Поток может предоставлять доступ к памяти в режиме чтения или записи.
Для описания всех этих режимов работы с памятью, создано перечисление OpenMode, в котором описаны соответствующие битовые флаги.
Комбинирование этих флагов с помощью побитового ИЛИ позволяет гибко настраивать режим работы с памятью.
Обратите внимание, что допускается режим одновременного чтения и записи.
Поток ввода / вывода должен быть однозначно связан с некоторой памятью. Ситуация, когда один объект класса MemoryStream связан с несколькими областями памяти — недопустима.
Точно так же недопустима ситуация, когда с одной памятью связаны несколько объектов MemoryStream.
Поэтому класс потока должен быть спроектирован так, чтобы предотвращать эти ситуации.
Операции ввода / вывода в память могут закончится неудачей, поэтому необходимы механизмы обнаружения ошибочных состояний.
Один из таких механизмов — это флаги состояния потока.
Стандартная библиотека C связывает с каждым файлом два индикатора ошибок: индикатор достижения конца файла,
и индикатор всех остальных ошибок ввода-вывода.
По аналогии с работой с файловыми потоками, для описания этих двух видов ошибок создано перечисление IOState. Поток может перейти в то или иное ошибочное состояние, и его функционал при этом будет ограничен.
В классе MemoryStream предусмотрены методы проверки текущего состояния потока.
При операциях ввода / вывода регулярно возникает необходимость знать количество записанных / прочитанных элементов потока (символов).
Однако добавление в каждый метод класса функционала для информирования о количестве элементов привело бы значительному усложнению и захламлению интерфейса класса.
Поэтому с каждым объектом класса MemoryStream связан счётчик элементов, обновляемый после каждой операции ввода / вывода.
Доступ к счётчику обеспечивается специальным методом count().
Интерфейс класса спроектирован так, что бы при необходимости упростить немедленный вызов count(), state() и других методов.
Большинство методов класса возвращают ссылку на объект MemoryStream, т.е. на тот же самый объект, от которого этот метод был вызван.
Это позволяет организовывать цепочки вызовов:
if ( memoryStream.read(buffer, 10).count() == 10 )
std::cout << "reading ok";
if ( memoryStream.str("sample string", Write).good() )
std::cout << "string is successfully assigned";
// и так тоже работает, но лучше так не делать
int i;
char s[20];
bool good = stream
.str("sample", Read)
.ignore(10, '|').put('c')
.ignore(10, '|').put('c')
.ignore(10, '|').good()
if ( good )
std::cout << "i'm lucky and have no idea why it works";
MemoryStream() — конструктор но умолчанию. Создаёт поток, с пустым "массивом".MemoryStream(const char * str, uint8_t mode) — конструктор объекта потока,
который выделяет память под str и работает в режиме соответствующий параметру mode (см. примечание 2).~MemoryStream() — деструктор объекта потока. Освобождает системные ресурсы.MemoryStream(const MemoryStream &) = delete — удалённый конструктор копий (см. примечание 3).operator=(const MemoryStream &) = delete — удалённый оператор копирования (см. примечание 3).str() — метод возвращает содержимое памяти, к которой привязан.str(const char* s) — метод перезаписывает содержимое памяти, строкой s.swap(MemoryStream& memoryStream) — метод swap'ет содержимое двух потоков.state() — метод возвращает набор IOState флагов, описывающих текущее состояние потока (см. примечание 4).clearState() — метод позволяет принудительно сбросить флаги состояния потока.good() — метод проверяет, что у потока сброшены все индикаторы ошибок.eof() — метод проверяет, что у потока выставлен индикатор достижения конца памяти.bad() — метод проверяет, что у потока выставлен индикатор ошибки ввода / вывода.count() — метод сообщает о количестве элементов потока успешно прочитанных / заспинных во время последней операции ввода / вывода (см. примечание 5).ignore(size_t n, int delim) — метод читает из потока элементы никуда не сохраняя (игнорируя) их.
Метод читает и игнорирует элементы до тех пор, пока не прочитает указанный элемент разделитель delim, либо пока не прочитает заданное количество элементов n.
Поток должен быть открыт в режиме чтения.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов count() возвращает количество успешно считанных элементов.read(void * buffer, size_t size) — метод считывает из памяти
заданное количество элементов size и сохраняет их в буфер buffer.
Поток должен быть открыт в режиме чтения.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов count() возвращает количество успешно считанных элементов.write(const void * buffer, size_t size) — метод записывает в память
size элементов из буфера buffer.
Поток должен быть открыт в режиме записи.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов count() возвращает количество успешно записанных элементов.get() — метод считывает из потока один элемент.
Поток должен быть открыт в режиме чтения. get(char & c) — метод считывает из потока один элемент и сохраняет по указанной ссылке c.
Поток должен быть открыт в режиме чтения.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов count() возвращает количество успешно считанных элементов.get(char * s, size_t len) — метод считывает строку из памяти и сохраняет её в буффер s длинны len.
Поток должен быть открыт в режиме чтения.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов count() возвращает количество успешно считанных элементов.put(char c) — метод записывает в потока один элемент.
Поток должен быть открыт в режиме записи.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов count() возвращает количество успешно записанных элементов.put(const char * s, size_t len) — метод записывает в поток строку длинны len из буфера s.
Поток должен быть открыт в режиме записи.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов count() возвращает количество успешно записанных элементов.print(const char * format, ...) — метод осуществляет форматированный вывод в поток.
Поток должен быть открыт в режиме записи.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов count() возвращает количество успешно записанных элементов.pos() — метод сообщает текущую позицию в памяти в виде fpos_t.pos(fpos_t p) — метод устанавливает текущую позицию в памяти, используя значение p,
полученное ранее при вызове метода pos().
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов state() позволяет определить успех / неуспех операции.long int tell() — метод позволяет узнать смещение от начала памяти для текущей позиции.seek(long int offset, SeekDirection dir) — метод позволяет установить текущую позицию через смещение от начала/конца памяти.
Метод возвращает ссылку на самого себя (см. примечание 6).
Последующий вызов state() позволяет определить успех / неуспех операции.public методам, класса MemoryStream необходимо добавить в нужных местах спецификаторы static и const. public и protected методов класса, а также типы и количество аргументов в них.MemoryStream.hpp, MemoryStream.cpp.